`default_nettype wire
`define ALU_SUB 5'b00001
`define ALU_RETURN_A 5'b00010
`define ALU_RETURN_B 5'b00011
`define ALU_XOR 5'b00100
`define ALU_OR 5'b00101
`define ALU_AND 5'b00110
`define ALU_SLL 5'b00111
`define ALU_SRL 5'b01000
`define ALU_SLT 5'b01001
`define ALU_SLTU 5'b01010
`define ALU_NONE 5'b01011
`define ALU_MUL 5'b01100
`define ALU_REM 5'b01101
`define ALU_DIVU 5'b01110
`define ALU_REMU 5'b01111
`define ALU_DIV 5'b10000
`define ALU_SRA 5'b10001
`define ALU_EQ 5'b10010
`define ALU_LOE 5'b10011
`define ALU_LOEU 5'b10100
`define ALU_ADD 5'b10101
`define ALU_NAANDB 5'b10110
`define ALU_DONOTHING 5'b10111
`define R_Type 3'b000
`define J_Type 3'b001
`define I_Type 3'b010
`define S_Type 3'b011
`define U_Type 3'b100
`define B_Type 3'b101
`define SEXT(x, target, exist) {{(target - exist){x[exist-1]}}, x[exist - 1:0]}
`define NSEXT(x, target, exist) {{(target - exist){1'b0}}, x[exist - 1:0]}

// csr address:
`define CSR_MEPC_ADDRESS 12'h341
`define CSR_MCAUSE_ADDRESS 12'h342
`define CSR_MTVEC_ADDRESS 12'h305
`define CSR_MSTATUS_ADDRESS 12'h300
`define CSR_MIE_ADDRESS 12'h304
`define CSR_MIP_ADDRESS 12'h344

`define MTIMECMP_ADDRESS 64'h2000000+64'h4000
`define MTIME_ADDRESS 64'h2000000+64'hBFF8
module ysyx_041207_alu(
    input clk,
    input rst,
    input flush,
    input bubble,
    input ex_pc_panic,
    input ex_memoryReadWen,
    input [2:0] ex_readNum,
    input [2:0] ex_writeBackDataSelect,
    input [7:0] ex_memoryWriteMask,
    input ex_sext,
    input ex_writeRD,
    input [4:0] ex_rwaddr,
    input ex_jal,
    input ex_jalr,
    input ex_dbranch,
    input ex_csrWen,
    input [2:0] ex_writeLen,
    input ex_pc_mret,
    

    input [63:0] pc,
    input [4:0] operate,
    input [63:0] rs1,
    input [63:0] rs2,
    input [63:0] csr,
    input [63:0] imm,
    input [4:0] rs1addr,
    input [1:0] sel_a,
    input [1:0] sel_b,
    input rs1to32,  // rs1 转换为32bit
    output reg [63:0] res,
    output reg alu_wait,

    output reg ex_memoryReadWen_o,
    output reg [2:0] ex_readNum_o,
    output reg [63:0] ex_pc_o,
    output reg [63:0] ex_imm_o,
    output reg [2:0] ex_writeBackDataSelect_o,
    output reg [62:0] ex_forward_rs1_o,
    output reg [63:0] ex_forward_rs2_o,
    output reg [7:0] ex_memoryWriteMask_o,
    output reg ex_sext_o,
    output reg ex_writeRD_o,
    output reg [4:0] ex_rwaddr_o,
    output reg ex_jal_o,
    output reg ex_jalr_o,
    output reg ex_dbranch_o,
    output reg ex_csrWen_o,
    output reg [63:0] ex_csr_readData_o,
    output reg [2:0] ex_writeLen_o,
    output reg ex_pc_mret_o,
    output reg ex_pc_panic_o
);

reg tex_memoryReadWen_o;
reg [2:0] tex_readNum_o;
reg [63:0] tex_pc_o;
reg [63:0] tex_imm_o;
reg [2:0] tex_writeBackDataSelect_o;
reg [62:0] tex_forward_rs1_o;
reg [63:0] tex_forward_rs2_o;
reg [7:0] tex_memoryWriteMask_o;
reg tex_sext_o;
reg tex_writeRD_o;
reg [4:0] tex_rwaddr_o;
reg tex_jal_o;
reg tex_jalr_o;
reg tex_dbranch_o;
reg tex_csrWen_o;
reg [63:0] tex_csr_readData_o;
reg [2:0] tex_writeLen_o;
reg tex_pc_mret_o;
reg tex_pc_panic_o;
`define rclear tex_memoryReadWen_o <= 0;\
            tex_readNum_o <= 0;\
            tex_pc_o <= 0;\
            tex_imm_o <= 0;\
            tex_writeBackDataSelect_o <= 0;\
            tex_forward_rs1_o <= 0;\
            tex_forward_rs2_o <= 0;\
            tex_memoryWriteMask_o <= 0;\
            tex_sext_o <= 0;\
            tex_writeRD_o <= 0;\
            tex_rwaddr_o <= 0;\
            tex_jal_o <= 0;\
            tex_jalr_o <= 0;\
            tex_dbranch_o <= 0;\
            tex_csrWen_o <= 0;\
            tex_csr_readData_o <= 0;\
            tex_writeLen_o <= 0;\
            tex_pc_mret_o <= 0;\
            tex_pc_panic_o <= 0;
`define rbuf tex_memoryReadWen_o <= ex_memoryReadWen;\
            tex_readNum_o <= ex_readNum;\
            tex_pc_o <= pc;\
            tex_imm_o <= imm;\
            tex_writeBackDataSelect_o <= ex_writeBackDataSelect;\
            tex_forward_rs1_o <= rs1[63:1];\
            tex_forward_rs2_o <= rs2;\
            tex_memoryWriteMask_o <= ex_memoryWriteMask;\
            tex_sext_o <= ex_sext;\
            tex_writeRD_o <= ex_writeRD;\
            tex_rwaddr_o <= ex_rwaddr;\
            tex_jal_o <= ex_jal;\
            tex_jalr_o <= ex_jalr;\
            tex_dbranch_o <= ex_dbranch;\
            tex_csrWen_o <= ex_csrWen;\
            tex_csr_readData_o <= csr;\
            tex_writeLen_o <= ex_writeLen;\
            tex_pc_mret_o <= ex_pc_mret;\
            tex_pc_panic_o <= ex_pc_panic;
wire [63:0] a;
wire [63:0] b;
assign a = (sel_a == 2'b1) ? (rs1to32 ? {32'b0, rs1 [31:0]} : rs1) : (sel_a == 2'h2) ? {59'b0, rs1addr} : pc;
assign b = (sel_b == 2'h3) ? {32'b0, rs2 [31:0]} : ((sel_b == 2'b1) ? rs2 : ((sel_b == 2'h2) ? csr : imm));
// 0: imm, 3 rs2[31:0], 2: csr, 1: rs2
reg mul_valid;
wire mul_out_valid;
wire [63:0] mul_res;
reg div_valid;
wire div_out_valid;
reg div_sign;
wire [63:0] div_out, remain_out;
reg [63:0] ta, tb;
ysyx_041207_mul rx_mul(clk, rst, mul_valid, flush || (bubble && ~alu_wait), ta, tb, mul_out_valid, mul_res);
ysyx_041207_div rx_div(clk, rst, div_valid, flush || (bubble && ~alu_wait), ta, tb, div_sign, div_out_valid, div_out, remain_out);
// ALU的第一个操作数是pc或者rs1
// 第二个操作数为imm或者rs2
reg [2:0] constantOpt;
always @(posedge clk) begin
    if (rst || flush || (bubble && ~alu_wait)) begin
        res <= 0;
        alu_wait <= 0;
        div_valid <= 0;
        mul_valid <= 0;
        div_sign <= 0;
        ex_memoryReadWen_o <= 0;
        ex_readNum_o <= 0;
        ex_pc_o <= 0;
        ex_imm_o <= 0;
        ex_writeBackDataSelect_o <= 0;
        ex_forward_rs1_o <= 0;
        ex_forward_rs2_o <= 0;
        ex_memoryWriteMask_o <= 0;
        ex_sext_o <= 0;
        ex_writeRD_o <= 0;
        ex_rwaddr_o <= 0;
        ex_jal_o <= 0;
        ex_jalr_o <= 0;
        ex_dbranch_o <= 0;
        ex_csrWen_o <= 0;
        ex_csr_readData_o <= 0;
        ex_writeLen_o <= 0;
        ex_pc_mret_o <= 0;
        ex_pc_panic_o <= 0;
        constantOpt <= 0;
        `rclear
    end else begin
        if (mul_out_valid || div_out_valid) begin
            ex_memoryReadWen_o <= tex_memoryReadWen_o;
            ex_readNum_o <= tex_readNum_o;
            ex_pc_o <= tex_pc_o;
            ex_imm_o <= tex_imm_o;
            ex_writeBackDataSelect_o <= tex_writeBackDataSelect_o;
            ex_forward_rs1_o <= tex_forward_rs1_o;
            ex_forward_rs2_o <= tex_forward_rs2_o;
            ex_memoryWriteMask_o <= tex_memoryWriteMask_o;
            ex_sext_o <= tex_sext_o;
            ex_writeRD_o <= tex_writeRD_o;
            ex_rwaddr_o <= tex_rwaddr_o;
            ex_jal_o <= tex_jal_o;
            ex_jalr_o <= tex_jalr_o;
            ex_dbranch_o <= tex_dbranch_o;
            ex_csrWen_o <= tex_csrWen_o;
            ex_csr_readData_o <= tex_csr_readData_o;
            ex_writeLen_o <= tex_writeLen_o;
            ex_pc_mret_o <= tex_pc_mret_o;
            ex_pc_panic_o <= tex_pc_panic_o;
            `rclear
        end
        else if (operate != `ALU_DIV && operate != `ALU_DIVU && operate != `ALU_REM && operate != `ALU_REMU && ~bubble) begin    // 那就是要接收新的输入
            if (ex_memoryReadWen) begin
                //$display("catch read wen:%x", pc);
            end
            ex_memoryReadWen_o <= ex_memoryReadWen;
            ex_readNum_o <= ex_readNum;
            ex_pc_o <= pc;
            ex_imm_o <= imm;
            ex_writeBackDataSelect_o <= ex_writeBackDataSelect;
            ex_forward_rs1_o <= rs1[63:1];
            ex_forward_rs2_o <= rs2;
            ex_memoryWriteMask_o <= ex_memoryWriteMask;
            ex_sext_o <= ex_sext;
            ex_writeRD_o <= ex_writeRD;
            ex_rwaddr_o <= ex_rwaddr;
            ex_jal_o <= ex_jal;
            ex_jalr_o <= ex_jalr;
            ex_dbranch_o <= ex_dbranch;
            ex_csrWen_o <= ex_csrWen;
            ex_csr_readData_o <= csr;
            ex_writeLen_o <= ex_writeLen;
            ex_pc_mret_o <= ex_pc_mret;
            ex_pc_panic_o <= ex_pc_panic;
        end
        if (mul_valid) begin
            mul_valid <= 0;
        end
        if (mul_out_valid && constantOpt == 3'h1) begin
            res <= mul_res;
            alu_wait <= 0;
            constantOpt <= 0;
        end
        if (div_valid) begin
            div_valid <= 0;
        end
        if (div_out_valid && constantOpt == 3'h2) begin
            res <= div_out;
            alu_wait <= 0;
            constantOpt <= 0;
        end
        if (div_out_valid && constantOpt == 3'h3) begin
            res <= div_out;
            alu_wait <= 0;
            constantOpt <= 0;
        end
        if (div_out_valid  && constantOpt == 3'h4) begin
            res <= remain_out;
            alu_wait <= 0;
            constantOpt <= 0;
        end
        if (div_out_valid  && constantOpt == 3'h5) begin
            res <= remain_out;
            alu_wait <= 0;
            constantOpt <= 0;
            //$display("remu result:%x %x", remain_out, div_out);
        end
        if (~bubble) begin
    case(operate)
        `ALU_ADD: begin
           //$display("add");
            res <= a + b;
        end
        `ALU_SUB: begin 
            res <= a - b;
        end
        `ALU_RETURN_A: begin
             res <= a;
        end
        `ALU_RETURN_B: begin
            res <= b;
        end
        `ALU_XOR: begin
             res <= a ^ b;
             //$display("xor %x %b", a, b);
        end
        `ALU_OR: begin
             res <= a | b;
        end
        `ALU_AND: begin
             res <= a & b;
        end
        `ALU_SLL: begin
            //$display("SLL %x %x %x %x", pc, a, b[5:0], a << b [5:0]);
            res <= a << b [5:0];
        end
        `ALU_SRL: begin
            //$display("SRL %x %x %x %x", pc, a, b[5:0], a >> b [5:0]);
             res <= a >> b [5:0];
        end
        `ALU_SLT: begin
            res <= $signed(a) < $signed(b) ? 64'b1 : 64'b0;
        end
        `ALU_SLTU: begin 
            res <= a < b ? 64'b1 : 64'b0;
        end
        `ALU_MUL: begin
            alu_wait <= 1;   // 卡住alu
            mul_valid <= 1;
            constantOpt <= 3'h1;
            ta <= a;
            tb <= b;
            `rbuf
        end
        `ALU_NAANDB: begin
             res <= ~a & b;
        end
        `ALU_REM: begin
            div_sign <= 1;
            alu_wait <= 1;   // 卡住alu
            div_valid <= 1;
            constantOpt <= 3'h4;
            ta <= a;
            tb <= b;
            `rbuf
        end
        `ALU_DIVU: begin 
            div_sign <= 0;
            alu_wait <= 1;   // 卡住alu
            div_valid <= 1;
            constantOpt <= 3'h2;
            ta <= a;
            tb <= b;
            `rbuf
        end
        `ALU_REMU: begin
             //res <= a % b;
            //$display("remu %x %x %x %x", a, b, a % b, a / b);
            div_sign <= 0;
            alu_wait <= 1;   // 卡住alu
            div_valid <= 1;
            constantOpt <= 3'h5;
            ta <= a;
            tb <= b;
            `rbuf
        end
        `ALU_DIV:begin
            div_sign <= 1;
            alu_wait <= 1;   // 卡住alu
            div_valid <= 1;
            constantOpt <= 3'h3;
            ta <= a;
            tb <= b;
            `rbuf
        end
        `ALU_SRA: begin
             res <= rs1to32 ? {32'b0, ($signed(a [31:0]) >>> b [5:0])} : ($signed(a) >>> b [5:0]);
        end
        `ALU_EQ: begin
            res <= (a == b) ? 1 : 0;
        end
        `ALU_LOE: begin 
            res <= ($signed(a) >= $signed(b))?1:0;
        end
        `ALU_LOEU: begin
            res <= (a >= b)?1:0;
        end
        default: begin
            res <= 0;
        end
    endcase
        end
    end
end
endmodule

// Burst types
`define AXI_BURST_TYPE_FIXED                                2'b00               //突发类型  FIFO
`define AXI_BURST_TYPE_INCR                                 2'b01               //ram  
`define AXI_BURST_TYPE_WRAP                                 2'b10
// Access permissions
`define AXI_PROT_UNPRIVILEGED_ACCESS                        3'b000
`define AXI_PROT_PRIVILEGED_ACCESS                          3'b001
`define AXI_PROT_SECURE_ACCESS                              3'b000
`define AXI_PROT_NON_SECURE_ACCESS                          3'b010
`define AXI_PROT_DATA_ACCESS                                3'b000
`define AXI_PROT_INSTRUCTION_ACCESS                         3'b100
// Memory types (AR)
`define AXI_ARCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define AXI_ARCACHE_DEVICE_BUFFERABLE                       4'b0001
`define AXI_ARCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define AXI_ARCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define AXI_ARCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b1010
`define AXI_ARCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b1110
`define AXI_ARCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1010
`define AXI_ARCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define AXI_ARCACHE_WRITE_BACK_NO_ALLOCATE                  4'b1011
`define AXI_ARCACHE_WRITE_BACK_READ_ALLOCATE                4'b1111
`define AXI_ARCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1011
`define AXI_ARCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111
// Memory types (AW)
`define AXI_AWCACHE_DEVICE_NON_BUFFERABLE                   4'b0000
`define AXI_AWCACHE_DEVICE_BUFFERABLE                       4'b0001
`define AXI_AWCACHE_NORMAL_NON_CACHEABLE_NON_BUFFERABLE     4'b0010
`define AXI_AWCACHE_NORMAL_NON_CACHEABLE_BUFFERABLE         4'b0011
`define AXI_AWCACHE_WRITE_THROUGH_NO_ALLOCATE               4'b0110
`define AXI_AWCACHE_WRITE_THROUGH_READ_ALLOCATE             4'b0110
`define AXI_AWCACHE_WRITE_THROUGH_WRITE_ALLOCATE            4'b1110
`define AXI_AWCACHE_WRITE_THROUGH_READ_AND_WRITE_ALLOCATE   4'b1110
`define AXI_AWCACHE_WRITE_BACK_NO_ALLOCATE                  4'b0111
`define AXI_AWCACHE_WRITE_BACK_READ_ALLOCATE                4'b0111
`define AXI_AWCACHE_WRITE_BACK_WRITE_ALLOCATE               4'b1111
`define AXI_AWCACHE_WRITE_BACK_READ_AND_WRITE_ALLOCATE      4'b1111

`define AXI_SIZE_BYTES_1                                    3'b000                //突发宽度一个数据的宽度
`define AXI_SIZE_BYTES_2                                    3'b001
`define AXI_SIZE_BYTES_4                                    3'b010
`define AXI_SIZE_BYTES_8                                    3'b011
`define AXI_SIZE_BYTES_16                                   3'b100
`define AXI_SIZE_BYTES_32                                   3'b101
`define AXI_SIZE_BYTES_64                                   3'b110
`define AXI_SIZE_BYTES_128                                  3'b111

// 传入地址为8字节对齐，且写掩码已经完成移动
module ysyx_041207_axi_rw # (
    parameter RW_DATA_WIDTH     = 64,
    parameter RW_ADDR_WIDTH     = 64,
    parameter AXI_DATA_WIDTH    = 64,
    parameter AXI_ID_WIDTH      = 4
)(
    input                               clock,
    input                               reset,

	input                               r_valid_i,         //IF&MEM输入信号
	output reg                             r_ready_o,         //IF&MEM输入信号
    output reg [RW_DATA_WIDTH-1:0]      data_read_o,        //IF&MEM输入信号
    input  [RW_ADDR_WIDTH-1:0]          r_addr_i,          //IF&MEM输入信号
    input  [2:0]                        r_size_i,          //IF&MEM输入信号
    output reg                          r_data_valid,   // 读取数据是否有效
    input                               r_data_ready,   // 是否读取完成 
    input                               w_valid_i,         //IF&MEM输入信号
	output  reg                            w_ready_o,         //IF&MEM输入信号
    input [RW_DATA_WIDTH-1:0]           w_data_i,        //IF&MEM输入信号
    input  [RW_ADDR_WIDTH-1:0]          w_addr_i,          //IF&MEM输入信号
    input  [7:0]                        w_mask_i,          //IF&MEM输入信号
    output reg                             w_valid_o,
    input                               tw_ready_i,
    // Advanced eXtensible Interface
    input                               axi_aw_ready_i,              
    output                              axi_aw_valid_o,
    output [31:0]         axi_aw_addr_o,
    output [AXI_ID_WIDTH-1:0]           axi_aw_id_o,
    output [7:0]                        axi_aw_len_o,
    output [2:0]                        axi_aw_size_o,
    output [1:0]                        axi_aw_burst_o,
    input                               axi_w_ready_i,                
    output                              axi_w_valid_o,
    output [AXI_DATA_WIDTH-1:0]         axi_w_data_o,
    output [AXI_DATA_WIDTH/8-1:0]       axi_w_strb_o,
    output                              axi_w_last_o,
    
    output                              axi_b_ready_o,                
    input                               axi_b_valid_i,
    input  [1:0]                        axi_b_resp_i,                 
    input  [AXI_ID_WIDTH-1:0]           axi_b_id_i,

    input                               axi_ar_ready_i,                
    output                              axi_ar_valid_o,
    output [31:0]         axi_ar_addr_o,
    output [AXI_ID_WIDTH-1:0]           axi_ar_id_o,
    output [7:0]                        axi_ar_len_o,
    output [2:0]                        axi_ar_size_o,
    output [1:0]                        axi_ar_burst_o,
    
    output                              axi_r_ready_o,                 
    input                               axi_r_valid_i,                
    input  [1:0]                        axi_r_resp_i,
    input  [AXI_DATA_WIDTH-1:0]         axi_r_data_i,
    input                               axi_r_last_i,
    input  [AXI_ID_WIDTH-1:0]           axi_r_id_i,
    input [2:0] w_size_i,
    output[5:0]	io_sram0_addr	,		
    output	io_sram0_cen		,	
    output	io_sram0_wen			,
    output[127:0]	io_sram0_wmask			,
    output[127:0]	io_sram0_wdata			,
    input[127:0]	io_sram0_rdata			,
    output[5:0]	io_sram1_addr			,
    output	io_sram1_cen			,
    output	io_sram1_wen			,
    output[127:0]	io_sram1_wmask			,
    output[127:0]	io_sram1_wdata			,
    input[127:0]	io_sram1_rdata			,
    output[5:0]	io_sram2_addr			,
    output	io_sram2_cen			,
    output	io_sram2_wen			,
    output[127:0]	io_sram2_wmask			,
    output[127:0]	io_sram2_wdata			,
    input[127:0]	io_sram2_rdata			,
    output[5:0]	io_sram3_addr			,
    output	io_sram3_cen			,
    output	io_sram3_wen			,
    output[127:0]	io_sram3_wmask		,
    output[127:0]	io_sram3_wdata		,	
    input[127:0]	io_sram3_rdata
);
wire cache_hit;
wire [63:0] cache_data;
reg cache_wupdate_en, cache_update_en;
reg [63:0] cache_addr;
    reg r_state_addr, r_state_read;
    reg waitForCache;
ysyx_041207_cache rx_cache(clock, reset, r_addr_i[63:3], cache_hit, cache_data, 
    cache_wupdate_en, w_addr_i [63:3], cache_update_en, cache_addr[63:3], data_read_o, 
    io_sram0_addr,io_sram0_cen,io_sram0_wen,io_sram0_wmask,io_sram0_wdata,io_sram0_rdata,io_sram1_addr,io_sram1_cen,
    io_sram1_wen,io_sram1_wmask,io_sram1_wdata,io_sram1_rdata,io_sram2_addr,io_sram2_cen,io_sram2_wen,io_sram2_wmask,
    io_sram2_wdata,io_sram2_rdata,io_sram3_addr,io_sram3_cen,io_sram3_wen,io_sram3_wmask,io_sram3_wdata,io_sram3_rdata);
    // 读通道状态切换

    
    // ------------------State Machine------------------TODO
    // 写通道状态切换
    reg w_state_addr, w_state_write, w_state_resp;
    always @(posedge clock) begin
        if (reset) begin
            w_ready_o <= 0;
            w_state_write <= 0;
            w_state_resp <= 0;
            cache_wupdate_en <= 0;
            cache_update_en <= 0;
        end
        if (~reset) begin
        if (w_valid_i && ~w_ready_o) begin    // 外部模块要求写入数据
            w_ready_o <= 1; // 表示已经收到数据
            w_state_addr <= 1;
            //$display("axi write address:%x %d %b", w_addr_i, w_size_i, w_mask_i);
            w_state_write <= 1;
            cache_wupdate_en <= 1;
        end
        if (w_valid_i && w_ready_o) begin    // 外部模块要求写入数据
            w_ready_o <= 0;
        end
        if (w_state_addr && axi_aw_ready_i) begin   // 已经收到了写入地址
            w_state_addr <= 0;
            w_state_resp <= 1;
        end
        if (w_state_write && axi_w_ready_i) begin   // 已经收到了写入数据
            w_state_write <= 0;
            w_state_resp <= 1;
        end
        if (axi_b_valid_i && w_state_resp) begin    // 收到了响应，完成写入
            w_state_resp <= 0;
            w_valid_o <= 1;
            cache_wupdate_en <= 0;
        end
        if (w_valid_o && tw_ready_i) begin
            w_valid_o <= 0;
        end
        end
    end

    
    always @(posedge clock) begin
        if (reset) begin
            r_state_addr <= 0;
            r_state_read <= 0;
            r_ready_o <= 1;
            waitForCache <= 0;
        end
        if (~reset) begin
            if (cache_update_en) begin
                cache_update_en <= 0;
            end
        if (r_valid_i && r_ready_o) begin
            r_ready_o <= 0;
            if (cache_hit) begin
                waitForCache <= 1;
                //$display("cache hit:%x %x", {r_addr_i[63:3], 3'b0}, cache_data);
            end else begin
                r_state_addr <= 1;  // 告知axi slave, 开始读取
                data_read_o <= 0;
                cache_addr <= r_addr_i;
                //$display("start to read r %x", r_addr_i);
            end
            
        end
        if (waitForCache) begin
            data_read_o <= cache_data;
            r_data_valid <= 1;
            waitForCache <= 0;
        end
        if (axi_ar_ready_i && r_state_addr) begin   // 从机已经接收到地址了
            r_state_addr <= 0;
            r_state_read <= 1;  // 准备好接受数据了
        end
        if (axi_r_valid_i && r_state_read) begin    // 从机数据读取完成
            //$display("read %x %x", r_addr_i ,axi_r_data_i);
            data_read_o <= axi_r_data_i;
            if (cache_addr >= 64'h80000000) begin
                cache_update_en <= 1;
            end
            r_state_read <= 0;
            r_data_valid <= 1;  // 告诉外部模块，数据已经读取完成
        end
        if (r_data_valid && r_data_ready) begin
            r_data_valid <= 0;
            r_ready_o <= 1;
        end
        end
    end

    // ------------------Write Transaction------------------
    parameter AXI_SIZE      = $clog2(AXI_DATA_WIDTH / 8);
    wire [AXI_ID_WIDTH-1:0] axi_id              = {AXI_ID_WIDTH{1'b0}};
    wire [7:0] axi_len      =  8'b0 ;
    wire [2:0] axi_size     = AXI_SIZE[2:0];
    // 写地址通道  以下没有备注初始化信号的都可能是你需要产生和用到的
    assign axi_aw_valid_o   = w_state_addr;
    assign axi_aw_addr_o    = w_addr_i[31:0];//w_addr_i;// //w_addr_i[31:0];
    assign axi_aw_id_o      = axi_id;                                                                           //初始化信号即可
    assign axi_aw_len_o     = axi_len;
    //assign axi_aw_size_o    = (w_addr_i >= 64'h80000000) ? axi_size : w_size_i; // 2^axi_size 字节
    //assign axi_aw_size_o    = w_size_i; // 2^axi_size 字节
    assign axi_aw_size_o    = w_size_i;//(w_addr_i <= 64'h80000000) ? 3'h2 : w_size_i;
    assign axi_aw_burst_o   = `AXI_BURST_TYPE_INCR;                                                             


    // 写数据通道
    assign axi_w_valid_o    = w_state_write;
    assign axi_w_data_o     = w_data_i;
    assign axi_w_strb_o     = w_mask_i;
    assign axi_w_last_o     = 1'b1;

    // 写应答通道
    assign axi_b_ready_o    = w_state_resp;


    // ------------------Read Transaction------------------
    
    // Read address channel signals
    assign axi_ar_valid_o   = r_state_addr;
    assign axi_ar_addr_o    = (r_addr_i < 64'h80000000) ? r_addr_i[31:0] : {r_addr_i[31:3], 3'b0};// //{r_addr_i[31:3], 3'b0};
    assign axi_ar_id_o      = axi_id;                                                                           //初始化信号即可                        
    assign axi_ar_len_o     = axi_len;                                                                   
    assign axi_ar_size_o    = (r_addr_i < 64'h80000000) ? r_size_i : axi_size;//(r_addr_i <= 64'h80000000) ? r_size_i : axi_size; //(r_addr_i <= 64'h80000000) ? 2 : axi_size;                                                   // mmio地址读取的时候不能全读8字节          
    assign axi_ar_burst_o   = `AXI_BURST_TYPE_INCR;

    // Read data channel signals
    assign axi_r_ready_o    = r_state_read;

endmodule

module ysyx_041207_axi_switch# (
    parameter RW_DATA_WIDTH     = 64,
    parameter RW_ADDR_WIDTH     = 64
) (   // axi 读选择器
    input clk,
    input rst,
    input                               mem_r_valid_i,         //IF&MEM输入信号
	output                              mem_r_ready_o,         //IF&MEM输入信号
    output  [RW_DATA_WIDTH-1:0]      mem_data_read_o,        //IF&MEM输入信号
    input  [RW_ADDR_WIDTH-1:0]          mem_r_addr_i,          //IF&MEM输入信号
    input  [2:0]                        mem_r_size_i,          //IF&MEM输入信号
    output                              mem_r_data_valid,   // 读取数据是否有效
    input                               mem_r_data_ready,   // 是否读取完成

    input                               if_r_valid_i,         //IF&MEM输入信号
	output                              if_r_ready_o,         //IF&MEM输入信号
    output  [RW_DATA_WIDTH-1:0]      if_data_read_o,        //IF&MEM输入信号
    input  [RW_ADDR_WIDTH-1:0]          if_r_addr_i,          //IF&MEM输入信号
    input  [2:0]                        if_r_size_i,          //IF&MEM输入信号
    output                              if_r_data_valid,   // 读取数据是否有效
    input                               if_r_data_ready,   // 是否读取完成

    output                               s_r_valid_i,         //IF&MEM输入信号
	input                              s_r_ready_o,         //IF&MEM输入信号
    input  [RW_DATA_WIDTH-1:0]      s_data_read_o,        //IF&MEM输入信号
    output  [RW_ADDR_WIDTH-1:0]          s_r_addr_i,          //IF&MEM输入信号
    output  [2:0]                        s_r_size_i,          //IF&MEM输入信号
    input                              s_r_data_valid,   // 读取数据是否有效
    output                              s_r_data_ready   // 是否读取完成
);

reg memUsing, busy;
always @(posedge clk) begin
    if (rst) begin
        busy <= 0;
        memUsing <= 0;
    end
    else begin
    // mem模块优先级更高，如果mem模块有信号，那就给mem模块，否则给if模块
    if (mem_r_valid_i && ~busy) begin    // mem抢占了
        memUsing <= 1;
        busy <= 1;
    end else if (if_r_valid_i && ~busy) begin   // if抢占
        memUsing <= 0;
        busy <= 1;
    end
    // 已经完成了使用
    if (s_r_data_valid && ( memUsing ? mem_r_data_ready : if_r_data_ready) && busy) begin
        busy <= 0;
    end
    end
end
assign s_r_valid_i = busy ? (memUsing ? mem_r_valid_i : if_r_valid_i) : 0;
    assign mem_r_ready_o = busy ? (memUsing ? s_r_ready_o : 0) : 0; assign if_r_ready_o = busy ? (memUsing ? 0 : s_r_ready_o) : 0; 
    assign  s_r_addr_i =  busy ? (memUsing ? mem_r_addr_i : if_r_addr_i) : 0;
    assign  s_r_size_i =  busy ? (memUsing ? mem_r_size_i : if_r_size_i) : 0;
    assign  mem_r_data_valid =  busy ? (memUsing ? s_r_data_valid : 0) : 0;assign  if_r_data_valid = busy ? (memUsing ? 0 : s_r_data_valid):0;
    assign  s_r_data_ready =  busy ? (memUsing ? mem_r_data_ready : if_r_data_ready) : 0;
    assign  mem_data_read_o = busy ? (s_data_read_o) : 0;
    assign  if_data_read_o =  busy ? s_data_read_o : 0;
// always @(posedge clk) begin
//     s_r_valid_i <= memUsing ? mem_r_valid_i : if_r_valid_i;
//     mem_r_ready_o <= memUsing ? s_r_ready_o : 0; if_r_ready_o <= memUsing ? 0 : s_r_ready_o; 
    
//     s_r_addr_i <= memUsing ? mem_r_addr_i : if_r_addr_i;
//     s_r_size_i <= memUsing ? mem_r_size_i : if_r_size_i;

//     mem_r_data_valid <= memUsing ? s_r_data_valid : 0; if_r_data_valid <= memUsing ? 0 : s_r_data_valid;
//     s_r_data_ready <= memUsing ? mem_r_data_ready : if_r_data_ready;
//     mem_data_read_o <= s_data_read_o;
//     if_data_read_o <= s_data_read_o;
// end
endmodule

module ysyx_041207_Bubble (
    input ex_alu_wait,
    input [4:0] ex_r1,
    input [4:0] ex_r2,
    input ex_writeRD_o,
    input [4:0] ex_rd_o,
    input [2:0] ex_writeBackDataSelect_o,
    input waitForAXI,
    output reg bubble
);
always @(*) begin
    //$display("wait %d", ex_alu_wait);
    // if (me_rd != 0 || ex_alu_wait || waitForAXI || wb_rd != 0) begin
    //     //$display("%d %d %d %d %d", me_rd, me_rd_o, ex_alu_wait, waitForAXI, wb_rd);
    //     bubble = 1;
    // end else begin
    //     bubble = 0;
    // end
    if (ex_alu_wait | waitForAXI) begin
        bubble = 1;
        //$display("here");
    end else if ((ex_rd_o == ex_r1 || ex_rd_o == ex_r2) && ex_writeBackDataSelect_o != 0 && (ex_rd_o != 0) && ex_writeRD_o) begin
        bubble = 1;
        //$display("here");
    end else begin
        bubble = 0;
    end
end
//assign bubble = ~waitForAXI ? (ex_alu_wait | waitForAXI) : (ex_alu_wait | waitForAXI | ((me_rd == ex_r1 || me_rd == ex_r2) && me_rd != 0) || ((me_rwaddr_o == ex_r1 || me_rwaddr_o == ex_r2) && me_rwaddr_o != 0));
endmodule

module ysyx_041207_cache (
    input clk,
    input rst,
    input [60:0] readAddress,
    output readHit,
    output [63:0] readData,
    input disableAddressWen,
    input [60:0] disableAddress,
    input updateDataWen,
    input [60:0] updateAddr,
    input [63:0] updateData,
    output[5:0]	io_sram0_addr	,		
    output	io_sram0_cen		,	
    output	io_sram0_wen			,
    output[127:0]	io_sram0_wmask			,
    output[127:0]	io_sram0_wdata			,
    input[127:0]	io_sram0_rdata			,
    output[5:0]	io_sram1_addr			,
    output	io_sram1_cen			,
    output	io_sram1_wen			,
    output[127:0]	io_sram1_wmask			,
    output[127:0]	io_sram1_wdata			,
    input[127:0]	io_sram1_rdata			,
    output[5:0]	io_sram2_addr			,
    output	io_sram2_cen			,
    output	io_sram2_wen			,
    output[127:0]	io_sram2_wmask			,
    output[127:0]	io_sram2_wdata			,
    input[127:0]	io_sram2_rdata			,
    output[5:0]	io_sram3_addr			,
    output	io_sram3_cen			,
    output	io_sram3_wen			,
    output[127:0]	io_sram3_wmask		,
    output[127:0]	io_sram3_wdata		,	
    input[127:0]	io_sram3_rdata			
);
//64 位地址
//[60:8][7-6 sram_index][5-0: sram_addr]
//sram 内部组成 [63:0][63:0 对齐后的数据v]
//wire [3:0] wen;
reg [63:0] valid [3:0];
reg [52:0] tagArray [3:0][63:0];
//assign {io_sram3_wen, io_sram2_wen, io_sram1_wen, io_sram0_wen} = wen;
assign {io_sram0_cen, io_sram1_cen, io_sram2_cen, io_sram3_cen} = 4'b0000;
wire [63:0] raw_read =    (readAddress [7:6] == 2'h0) ? io_sram0_rdata[63:0]:
                          (readAddress [7:6] == 2'h1) ? io_sram1_rdata[63:0]:
                          (readAddress [7:6] == 2'h2) ? io_sram2_rdata[63:0]:
                          (readAddress [7:6] == 2'h3) ? io_sram3_rdata[63:0]: 0;
assign readData = raw_read [63:0];
assign io_sram0_addr = updateDataWen ? updateAddr [5:0]: readAddress [5:0];
assign io_sram1_addr = updateDataWen ? updateAddr [5:0]: readAddress [5:0];
assign io_sram2_addr = updateDataWen ? updateAddr [5:0]: readAddress [5:0];
assign io_sram3_addr = updateDataWen ? updateAddr [5:0]: readAddress [5:0];
wire [127:0] sram_data = {64'b0, updateData};
assign io_sram0_wdata = sram_data;
assign io_sram1_wdata = sram_data;
assign io_sram2_wdata = sram_data;
assign io_sram3_wdata = sram_data;
//wire [127:0] sram_mask = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
wire [127:0] sram_mask =   128'h0;
assign io_sram0_wmask = sram_mask;
assign io_sram1_wmask = sram_mask;
assign io_sram2_wmask = sram_mask;
assign io_sram3_wmask = sram_mask;
assign io_sram0_wen = ~(updateDataWen && (updateAddr [7:6] == 2'h0));
assign io_sram1_wen = ~(updateDataWen && (updateAddr [7:6] == 2'h1));
assign io_sram2_wen = ~(updateDataWen && (updateAddr [7:6] == 2'h2));
assign io_sram3_wen = ~(updateDataWen && (updateAddr [7:6] == 2'h3));
assign readHit = (~disableAddressWen) && (~updateDataWen) && (tagArray[readAddress [7:6]][readAddress [5:0]] == readAddress [60:8]) && valid[readAddress [7:6]][readAddress [5:0]];
//assign readHit = 0;
always @(posedge clk) begin
    if (rst) begin
        for (integer i = 0;i < 4;i ++) begin
            valid [i] <= 0;
        end
    end else begin
        if (disableAddressWen && tagArray [disableAddress [7:6]][disableAddress [5:0]] == disableAddress [60:8]) begin
            valid[disableAddress [7:6]][disableAddress [5:0]] <= 0;
        end
        if (updateDataWen && ~(disableAddressWen && disableAddress[60:0] == updateAddr[60:0])) begin
            valid[updateAddr [7:6]][updateAddr [5:0]] <= 1;
            tagArray[updateAddr [7:6]][updateAddr [5:0]] <= updateAddr [60:8];
            //$display("update %x %x", {updateAddr, 3'b0}, updateData);
        end
    end
end
endmodule

module ysyx_041207_dataforward(
    input [4:0] r1addr,
    input [4:0] r2addr,
    input [63:0] r1data,
    input [63:0] r2data,
    input ex_writeRD_o,
    input [4:0]ex_rwaddr_o,
    input [2:0] ex_writeBackDataSelect_o,
    input [63:0] ex_aluRes,
    input me_writeRD_o,
    input [4:0] me_rwaddr_o,
    input [63:0] wb_writeBackData,
    output reg [63:0] r1data_o,
    output reg [63:0] r2data_o
);
    // assign r1data_o = r1data;
    // assign r2data_o = r2data;
    always @(*) begin
        //r1data_o = r1data;
        //r2data_o = r2data;
        if (ex_rwaddr_o == r1addr && ex_writeBackDataSelect_o == 0 && ex_writeRD_o) begin
            r1data_o = ex_aluRes;
        end else if (me_rwaddr_o == r1addr && me_writeRD_o) begin
            r1data_o = wb_writeBackData;
        end else begin
            r1data_o = r1data;
        end
        if (ex_rwaddr_o == r2addr && ex_writeBackDataSelect_o == 0 && ex_writeRD_o) begin
            r2data_o = ex_aluRes;
        end else if (me_rwaddr_o == r2addr && me_writeRD_o) begin
            r2data_o = wb_writeBackData;
        end else begin
            r2data_o = r2data;
        end
    end
endmodule

module ysyx_041207_decoder(
    input clk,
    input rst,
    input flush,
    input bubble,
    input [31:0] inst,
    input [63:0] pc,
    output reg [4:0] aluOperate,
    output reg [1:0] sel_a,
    output reg [1:0] sel_b,
    output reg [7:0] memoryWriteMask,
    output reg writeRD,
    output reg jalr,
    output reg jal,
    output reg [2:0] writeBackDataSelect,
    output reg memoryReadWen,
    output reg sext,
    output reg [2:0] readNum,
    output reg rs1to32,
    output reg wMcause,
    output reg [63:0] mcause_o,
    output reg pc_panic, // 是否为异常跳转
    output reg pc_mret,   // 是否为mret
    output reg csrWen,
    output reg branch,
    output reg [63:0] imm_o,
    output reg [4:0] rs1addr,
    output reg [4:0] rs2addr,
    output reg [4:0] rwaddr,
    output reg [2:0] csr_order,
    output reg [2:0] writeLen,
    output reg [63:0] pc_o
);
wire [63:0] imm;
wire [2:0] instType;
ysyx_041207_GetInstType getInstType(inst [6:0], instType);
ysyx_041207_SEXT SEXT(inst [31:7], instType, imm);
wire [6:0] opCode;
wire [6:0] funct7;
wire [2:0] funct3;
assign opCode = inst [6:0];
assign funct7 = inst [31:25];
assign funct3 = inst [14:12];
always @(posedge clk)
begin
    if (~rst && ~flush && ~bubble) begin
    pc_o <= pc;
    rs1addr <= inst [19:15];
    rs2addr <= inst [24:20];
    rwaddr <= inst [11:7];
    case (opCode)
    default: begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        writeRD <= 1'b0;
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        aluOperate <= `ALU_NONE;
        writeLen <= 0;
    end
    7'b1110011: // 系统指令
    begin
        case (funct3)
        3'b101: begin   // csrrwi
            imm_o <= imm;
            //$display("csrrsi  : %x %x", inst [19:15], inst[31:20]);
            rs1addr <= inst [19:15];
            rs2addr <= inst [24:20];
            memoryWriteMask <= 8'b0;
            wMcause <= 1'b0;
            pc_panic <= 1'b0;
            pc_mret <= 1'b0;
            memoryReadWen <= 1'b0;
            rs1to32 <= 1'b0;
            sext <= 1'b0;
            branch <= 1'b0;
            jalr <= 1'b0;
            jal <= 1'b0;
            writeLen <= 0;
            writeRD <= 1'b1;
            writeBackDataSelect <= 3'b101;
            csrWen <= 1'b1;
            //sel_b <= 2'h2;
            sel_a <= 2'h2;  //zimm
            aluOperate <= `ALU_RETURN_A;
            csr_order <= 3'h7;
        end
        3'b110: begin   // csrrsi
            //imm_o <= {{59'b0}, inst[19:15]};   // uimm
            imm_o <= imm;
            //$display("csrrsi  : %x %x", inst [19:15], inst[31:20]);
            memoryWriteMask <= 8'b0;
            wMcause <= 1'b0;
            pc_panic <= 1'b0;
            pc_mret <= 1'b0;
            memoryReadWen <= 1'b0;
            rs1to32 <= 1'b0;
            sext <= 1'b0;
            branch <= 1'b0;
            jalr <= 1'b0;
            jal <= 1'b0;
            writeLen <= 0;
            writeRD <= 1'b1;
            writeBackDataSelect <= 3'b101;
            csrWen <= 1'b1;
            sel_a <= 2'h2;
            sel_b <= 2'h2;
            aluOperate <= `ALU_OR;
            csr_order <= 3'h7;
        end
        3'b001: begin   // csrrw
        // 将csr的值写入rd 并将csr的值更新为rs1
        // csr写回的值直接设置为alu res
            //$display("csrrw");
            imm_o <= imm;
            memoryWriteMask <= 8'b0;
            wMcause <= 1'b0;
            
            pc_panic <= 1'b0;
            pc_mret <= 1'b0;
            memoryReadWen <= 1'b0;
            
            rs1to32 <= 1'b0;
            sext <= 1'b0;
            branch <= 1'b0;
            jalr <= 1'b0;
            jal <= 1'b0;
            writeLen <= 0;

            writeRD <= 1'b1;
            writeBackDataSelect <= 3'b101;
            csrWen <= 1'b1;
            sel_a <= 2'h1;
            aluOperate <= `ALU_RETURN_A;
            csr_order <= 3'h4;
        end
        3'b111: begin   // csrrci
            imm_o <= imm;
            //$display("decode %x", inst);
            memoryWriteMask <= 8'b0;
            wMcause <= 1'b0;
            
            pc_panic <= 1'b0;
            pc_mret <= 1'b0;
            memoryReadWen <= 1'b0;
            
            rs1to32 <= 1'b0;
            sext <= 1'b0;
            branch <= 1'b0;
            jalr <= 1'b0;
            jal <= 1'b0;
            writeLen <= 0;

            writeRD <= 1'b1;
            writeBackDataSelect <= 3'b101;
            csrWen <= 1'b1;
            sel_a <= 2'h2;
            sel_b <= 2'h2;
            aluOperate <= `ALU_NAANDB;
            csr_order <= 3'h5;
        end
        3'b011: begin   // csrrc
            imm_o <= imm;
            memoryWriteMask <= 8'b0;
            
            
            wMcause <= 1'b0;
            
            pc_panic <= 1'b0;
            pc_mret <= 1'b0;
            memoryReadWen <= 1'b0;
            
            rs1to32 <= 1'b0;
            sext <= 1'b0;
            branch <= 1'b0;
            jalr <= 1'b0;
            jal <= 1'b0;
            writeLen <= 0;

            writeRD <= 1'b1;
            writeBackDataSelect <= 3'b101;
            csrWen <= 1'b1;
            sel_a <= 2'h1;
            sel_b <= 2'h2;
            aluOperate <= `ALU_NAANDB;
            csr_order <= 3'h5;
        end
        3'b010: begin   // csrrs
            imm_o <= imm;
            memoryWriteMask <= 8'b0;
            wMcause <= 1'b0;
            
            pc_panic <= 1'b0;
            pc_mret <= 1'b0;
            memoryReadWen <= 1'b0;
            
            rs1to32 <= 1'b0;
            sext <= 1'b0;
            branch <= 1'b0;
            jalr <= 1'b0;
            jal <= 1'b0;
            writeLen <= 0;
            // 将csr的值写入rd 并将csr的值更新为csr | rs1
            writeRD <= 1'b1;
            writeBackDataSelect <= 3'b101;   // 写回csr
            sel_a <= 2'b1;   // 选择rs1作为a
            sel_b <= 2'h2;   // 选择csr作为b
            csrWen <= 1'b1;
            aluOperate <= `ALU_OR;
            csr_order <= 3'h3;
        end
        3'b0: begin
            case (imm)
                64'h1: begin     // ebreak
                    imm_o <= imm;
                    memoryWriteMask <= 8'b0;
                    wMcause <= 1'b0;
                    
                    pc_panic <= 1'b0;
                    pc_mret <= 1'b0;
                    csrWen <= 1'b0;
                    memoryReadWen <= 1'b0;
                    writeRD <= 1'b0;
                    
                    rs1to32 <= 1'b0;
                    sext <= 1'b0;
                    branch <= 1'b0;
                    jalr <= 1'b0;
                    jal <= 1'b0;
                    aluOperate <= `ALU_DONOTHING;
                    writeLen <= 0;
                    csr_order <= 3'b1;
                    // 开始等待流水线清空
                end
                64'b0: begin    // ecall
                    imm_o <= imm;
                    memoryWriteMask <= 8'b0;
                    pc_mret <= 1'b0;
                    csrWen <= 1'b0;
                    memoryReadWen <= 1'b0;
                    writeRD <= 1'b0;
                    
                    rs1to32 <= 1'b0;
                    sext <= 1'b0;
                    branch <= 1'b0;
                    jalr <= 1'b0;
                    jal <= 1'b0;
                    aluOperate <= `ALU_DONOTHING;
                    writeLen <= 0;
                    csr_order <= 3'h2;
                    // 将mepc设置为当前pc
                    // mcause设置为11
                    // mstatus中的mpie位设置为pie
                    // mstatus中的pie置为0
                    // pc更新为mtvec
                    
                    wMcause <= 1'b1;
                    mcause_o <= 64'hb;
                    pc_panic <= 1'b1;
                end
                64'b001100000010: begin // mret
                    imm_o <= imm;
                    memoryWriteMask <= 8'b0;
                    
                    
                    wMcause <= 1'b0;
                    
                    pc_panic <= 1'b0;
                    csrWen <= 1'b0;
                    memoryReadWen <= 1'b0;
                    writeRD <= 1'b0;
                    
                    rs1to32 <= 1'b0;
                    sext <= 1'b0;
                    branch <= 1'b0;
                    jalr <= 1'b0;
                    jal <= 1'b0;
                    aluOperate <= `ALU_DONOTHING;
                    writeLen <= 0;
                    // 返回mepc
                    pc_mret <= 1'b1;
                    csr_order <= 3'h5;
                end
                default: begin
                    imm_o <= imm;
                    memoryWriteMask <= 8'b0;
                    
                    
                    wMcause <= 1'b0;
                    
                    pc_panic <= 1'b0;
                    pc_mret <= 1'b0;
                    csrWen <= 1'b0;
                    memoryReadWen <= 1'b0;
                    writeRD <= 1'b0;
                    
                    rs1to32 <= 1'b0;
                    sext <= 1'b0;
                    branch <= 1'b0;
                    jalr <= 1'b0;
                    jal <= 1'b0;
                    csr_order <= 0;
                    aluOperate <= `ALU_NONE;
                    writeLen <= 0;
                end
            endcase
        end
        default: begin
                imm_o <= imm;
                memoryWriteMask <= 8'b0;
                
                
                wMcause <= 1'b0;
                
                pc_panic <= 1'b0;
                pc_mret <= 1'b0;
                csrWen <= 1'b0;
                memoryReadWen <= 1'b0;
                writeRD <= 1'b0;
                
                rs1to32 <= 1'b0;
                sext <= 1'b0;
                branch <= 1'b0;
                jalr <= 1'b0;
                jal <= 1'b0;
                csr_order <= 0;
                aluOperate <= `ALU_NONE;
                writeLen <= 0;
        end
        endcase
    end
    7'b0110011: // R型指令
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'b1;
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b000;
        case (funct3)
            3'b0: 
            case (funct7)
                7'b0:  aluOperate <= `ALU_ADD;//add
                7'h20: aluOperate <= `ALU_SUB;//sub
                7'b0000001: aluOperate <= `ALU_MUL;//mul
                default: aluOperate <= `ALU_NONE;
            endcase
            3'b100: case (funct7) 
                7'h0: aluOperate <= `ALU_XOR; //xor
                7'h1: aluOperate <= `ALU_DIV; //div
                default: aluOperate <= `ALU_NONE;
            endcase
            3'b110: case (funct7)
            7'h0: begin
                 aluOperate <= `ALU_OR;  //or
            end
            7'h1: begin
                aluOperate <= `ALU_REM; //rem
            end
            default: begin
                aluOperate <= `ALU_NONE;
            end
            endcase
            3'b111: case(funct7)
             7'h0: aluOperate <= `ALU_AND; //and
             7'h1: aluOperate <= `ALU_REMU; //remu
             default: aluOperate <= `ALU_NONE;
            endcase
            3'b001: aluOperate <= `ALU_SLL;  // sll
            3'b101: case (funct7)
                7'h0: aluOperate <= `ALU_SRL;    //srl
                7'h1: aluOperate <= `ALU_DIVU;   //divu
                7'h20: aluOperate <= `ALU_SRA;   //sra
                default: aluOperate <= `ALU_NONE;
            endcase
            3'b010: aluOperate <= `ALU_SLT;  //slt
            3'b011: aluOperate <= `ALU_SLTU; //sltu
            default: aluOperate <= `ALU_NONE;
        endcase
    end
    7'b0010011:    // I型指令
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'b0;
        writeBackDataSelect <= 3'b000;
        writeRD <= 1'b1;
        case (funct3)
        3'b000: begin 
            aluOperate <= `ALU_ADD;//addi
        end
        3'b100: aluOperate <= `ALU_XOR;//xori
        3'b110: aluOperate <= `ALU_OR;  //ori
        3'b111: aluOperate <= `ALU_AND; //andi
        3'b001: aluOperate <= `ALU_SLL;  // slli
        3'b101: case (funct7[6:1])
            6'h0: aluOperate <= `ALU_SRL;    //srli
            6'h10: aluOperate <= `ALU_SRA;    //srai
            default: aluOperate <= `ALU_NONE;
        endcase
        3'b010: aluOperate <= `ALU_SLT;  //slti
        3'b011: aluOperate <= `ALU_SLTU; //sltiu
        default: aluOperate <= `ALU_NONE;
        endcase
    end
    7'b0010111: // U型指令 auipc
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b0;
        sel_b <= 2'b0;
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b000;
        aluOperate <= `ALU_ADD;
        //$display("auipc..");
    end
    7'b0000011: // I型指令 但是 读取内存
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        
        rs1to32 <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'b0;   //rs1 + imm
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b001;
        memoryReadWen <= 1'b1;
        aluOperate <= `ALU_ADD;
        case(funct3)
        default: begin
            sext <= 1'b0;
            readNum <= 3'h0;
        end
        3'h0: begin // lb
            sext <= 1'b1;
            readNum <= 3'h0;
        end
        3'h1: begin // lh
            sext <= 1'b1;
            readNum <= 3'h1;
        end
        3'h2: begin // lw
            sext <= 1'b1;
            readNum <= 3'h2;
        end
        3'h3: begin // ld
            sext <= 1'b1;
            readNum <= 3'h3;
        end
        3'h4: begin // lbu
            sext <= 1'b0;
            readNum <= 3'h0;
        end
        3'h5: begin // lhu
            sext <= 1'b0;
            readNum <= 3'h1;
        end
        3'h6: begin // lwu
            sext <= 1'b0;
            readNum <= 3'h2;
        end
        endcase
    end
    7'b0110111: // U型指令 lui
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0; 
        wMcause <= 1'b0; 
            
        pc_panic <= 1'b0;    
        pc_mret <= 1'b0; 
        csrWen <= 1'b0;  
        memoryReadWen <= 1'b0;   
          
        rs1to32 <= 1'b0; 
        sext <= 1'b0;    
        branch <= 1'b0;  
        jalr <= 1'b0;    
        jal <= 1'b0; 
        csr_order <= 0;  
        writeLen <= 0;   
        //sel_a <= 2'b00;
        sel_b <= 2'b0;
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b000;
        aluOperate <= `ALU_RETURN_B;
    end
    7'b1101111: // J型指令 jal
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        csr_order <= 0;
        aluOperate <= `ALU_DONOTHING;
        writeLen <= 0;
        
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b10;
        jal <= 1'b1;
        //$display("decode jal");
    end
    7'b0100011: // S型指令
    begin
        imm_o <= imm;
        wMcause <= 1'b0;
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        writeRD <= 1'b0;
        
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'b0;   // 地址永远为rs1 + imm
        aluOperate <= `ALU_ADD;
        case (funct3)
        3'b000:begin  //sb
            //$display("catch sb");
            memoryWriteMask <= 8'b00000001;
            writeLen <= 3'h0;
        end
        3'b001:begin  //sh
            memoryWriteMask <= 8'b00000011;
            writeLen <= 3'h1;
        end
        3'b010:begin  //sw
            memoryWriteMask <= 8'b00001111;
            writeLen <= 3'h2;
        end
        3'b011:begin  //sd
            memoryWriteMask <= 8'b11111111;
            writeLen <= 3'h3;
        end
        default: begin
            memoryWriteMask <= 8'b0;
            writeLen <= 3'h0;
        end
        endcase
    end
    7'b0111011: // R型指令 带w 截取32位的指令
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'h3;
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b100;   // 对32位做符号扩展
        rs1to32 <= 1'b1; 
        case (funct7)
        default: begin
            aluOperate <= `ALU_NONE;
        end
        7'b0100000: begin
            case (funct3)
            3'b000: begin
                aluOperate <= `ALU_SUB;
            end
            3'b101: begin
                aluOperate <= `ALU_SRA;
            end
            default: aluOperate <= `ALU_NONE;
            endcase
        end
        7'b0000001: begin
            case (funct3)
            3'b0: begin
                aluOperate <= `ALU_MUL;  // mulw
            end
            3'b110: begin
                aluOperate <= `ALU_REM;  // remw
            end
            3'b101: begin
                aluOperate <= `ALU_DIVU; // divuw
            end
            3'b111: begin
                aluOperate <= `ALU_REMU; // remuw
            end
            3'b100: begin
                aluOperate <= `ALU_DIV;  // divw
            end
            default: aluOperate <= `ALU_NONE;
            endcase
        end
        7'b0000000: begin
            case (funct3)
            3'b000: begin
                case (funct7)
                    7'b0100000: aluOperate <= `ALU_SUB;  // subw
                    7'b0000000: aluOperate <= `ALU_ADD;  // addw
                    default aluOperate <= `ALU_NONE;
                endcase
            end
            3'b001: begin
                aluOperate <= `ALU_SLL;  // sllw
            end
            3'b101: begin
                case (funct7)
                    7'b0100000: aluOperate <= `ALU_SRA;  // sraw
                    7'b0000000: aluOperate <= `ALU_SRL;  // srlw
                    default aluOperate <= `ALU_NONE;
                endcase
            end
            default: begin
                aluOperate <= `ALU_NONE;
            end
            endcase
        end
        endcase
    end
    7'b0011011: // I型指令
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'b0;
        writeRD <= 1'b1;
        writeBackDataSelect <= 3'b100;   // 对32位做符号扩展
        case (funct3)
        3'b000: begin   
            rs1to32 <= 1'b0;
            aluOperate <= `ALU_ADD; // addiw
        end
        3'b001: begin
            case (funct7)
            7'h0: begin
                rs1to32 <= 1'b1;
                aluOperate <= `ALU_SLL;  // slliw
            end
            default: begin
                rs1to32 <= 1'b0;
                aluOperate <= `ALU_NONE;
            end
            endcase
        end
        3'b101: begin
            rs1to32 <= 1'b1;
            case (funct7)
            7'b0000000: begin
                aluOperate <= `ALU_SRL;  // srliw
            end
            7'b0100000: begin
                aluOperate <= `ALU_SRA;  // sraiw
            end
            default: aluOperate <= `ALU_NONE;
            endcase
        end
        default: begin
            aluOperate <= `ALU_NONE;
            rs1to32 <= 1'b0;
        end
        endcase
    end
    7'b1100111: // I型指令 jalr
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        aluOperate <= `ALU_DONOTHING;
        writeLen <= 0;
        writeRD <= 1'b1;
        jalr <= 1'b1;
        writeBackDataSelect <= 3'b10;
    end
    7'b1100011: // B型指令
    begin
        imm_o <= imm;
        memoryWriteMask <= 8'b0;
        
        
        wMcause <= 1'b0;
        
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        writeRD <= 1'b0;
        
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        writeLen <= 0;
        sel_a <= 2'b1;
        sel_b <= 2'b1;
        branch <= 1'b1;
        case(funct3)
        default: aluOperate <= `ALU_NONE;
        3'h0: begin // beq  相等的时候跳转
            aluOperate <= `ALU_XOR;  //只有相等的时候为0
        end
        3'h1: begin // bne
            // 不相等的时候为0
            aluOperate <= `ALU_EQ;
        end
        3'h4: begin // blt
            // 小于的时候跳转
            aluOperate <= `ALU_LOE;
        end
        3'h5: begin // bge
           // 小于的时候为1
           aluOperate <= `ALU_SLT;
        end
        3'b110: begin // bltu
            aluOperate <= `ALU_LOEU;
        end
        3'b111: begin // bgeu
            aluOperate <= `ALU_SLTU;
        end
        endcase
    end
    endcase
    end else if(~bubble || rst || flush) begin  // 已经传递下去了
        pc_o <= 0;
        imm_o <= 0;
        memoryWriteMask <= 8'b0;
        wMcause <= 1'b0;
        pc_panic <= 1'b0;
        pc_mret <= 1'b0;
        csrWen <= 1'b0;
        memoryReadWen <= 1'b0;
        writeRD <= 1'b0;
        rs1to32 <= 1'b0;
        sext <= 1'b0;
        branch <= 1'b0;
        jalr <= 1'b0;
        jal <= 1'b0;
        csr_order <= 0;
        aluOperate <= `ALU_DONOTHING;
        writeLen <= 0;
    end
end
endmodule

module ysyx_041207_div (
    input clk,
    input rst,
    input div_valid,
    input flush,
    input [63:0] dividend,  // 被除数
    input [63:0] divisor,    // 除数
    input sign_div,
    output reg out_valid,
    output reg [63:0] div_res_o,
    output reg [63:0] remain_o
);
reg div_ready;
reg [127:0] l_dividend, l_divisor;
reg [7:0] count;
reg sign;
wire [63:0] div_res = l_dividend[63:0];
wire [63:0] remain = l_dividend[127:64];
always @(posedge clk) begin
    if (rst || flush) begin
        count <= 0;
        div_ready <= 1;
        out_valid <= 0;
    end else begin
        if (div_valid && div_ready) begin
            //$display("div %x %x", (dividend[63]&&sign_div)?(~dividend + 1):dividend, (divisor[63]&&sign_div)?(~divisor + 1):divisor);
            sign <= (dividend[63] != divisor[63]) && sign_div;
            if (~sign_div) begin
                //$display("div %x %x", dividend, divisor);
            end
            
            l_dividend <= {64'b0, (dividend[63]&&sign_div)?(~dividend + 1):dividend};
            l_divisor <= {(divisor[63]&&sign_div)?(~divisor + 1):divisor, 64'b0};
            count <= 0;
            div_ready <= 0;
            div_res_o <= 0;
            remain_o <= 0;
            //$display("get div input %x %x", dividend, divisor);
        end
        if (~flush && ~div_ready && count != 8'h40) begin
           //div_res <= div_res + 
           //l_dividend <= l_dividend << 1;
           
           if ((l_dividend<<1) >= l_divisor) begin
                l_dividend <= (l_dividend<<1) - l_divisor + 1;
           end else begin
                l_dividend <= l_dividend<<1;
           end
           count <= count + 1;
           //$display("%d", count);
        end
        if (~flush && ~div_ready && count == 8'h40 && ~out_valid) begin
            //div_res <= div_res + ((l_divtiplier[0]) ? l_divtiplicand : 0);
            //$display("div %x %x %x", divtiplicand, divtiplier, div_res);
            out_valid <= 1;
            count <= 0;
            if (sign) begin
                div_res_o <= (~div_res) | (1 << 63);
                remain_o <= remain;
            end else begin
                if (dividend / divisor != div_res || remain != dividend % divisor) begin
                    //$display("div %d %x %x %x %x %x %x %x", sign, dividend, divisor, div_res, remain, dividend / divisor, dividend % divisor, l_dividend);
                end
                //$display("div %d %x %x %x %x %x %x %x",sign, dividend, divisor, div_res, remain, dividend / divisor, dividend % divisor, l_dividend);
                div_res_o <= div_res;
                remain_o <= remain;
                //div_res_o <= dividend / divisor;
                //remain_o <= dividend % divisor;
            end
        end
        if (out_valid) begin
            out_valid <= 0;
            div_ready <= 1;
        end
    end
end
endmodule

module ysyx_041207_EX_ME(
    input clk,
    input rst,
    input me_wait_for_axi,
    input flush,
    input bubble,
    input [63:0] aluRes,
    input memoryReadWen,
    input [2:0] readNum,
    input [63:0] pc,
    input [63:0] imm,
    input [2:0] wd_sel,
    input [63:0] rs1,
    input [63:0] rs2,
    input [7:0] memoryWriteMask,
    input sext,
    input writeRD,
    input [4:0] rwaddr,
    input jal,
    input jalr,
    input branch,
    input csrWen,
    input [63:0] csrValue,
    input [2:0] writeLen,
    input pc_mret,
    output reg [63:0] aluRes_o,
    output reg memoryReadWen_o,
    output reg [2:0] readNum_o,
    output reg [63:0] pc_o,
    output reg [63:0] imm_o,
    output reg [2:0] wd_sel_o,
    output reg [63:0] rs1_o,
    output reg [63:0] rs2_o,
    output reg [7:0] memoryWriteMask_o,
    output reg sext_o,
    output reg writeRD_o,
    output reg [4:0] rwaddr_o,
    output reg jal_o,
    output reg jalr_o,
    output reg branch_o,
    output reg csrWen_o,
    output reg [63:0] csrValue_o,
    output reg [2:0] writeLen_o,
    output reg pc_mret_o
);
always @(posedge clk) begin
    if (flush || rst || bubble) begin
        aluRes_o <= 0;
        memoryReadWen_o <= 0;
        readNum_o <= 0;
        pc_o <= 0;
        imm_o <= 0;
        wd_sel_o <= 0;
        rs1_o <= 0;
        rs2_o <= 0;
        memoryWriteMask_o <= 0;
        sext_o <= 0;
        writeRD_o <= 0;
        rwaddr_o <= 0;
        jal_o <= 0;
        jalr_o <= 0;
        branch_o <= 0;
        csrWen_o <= 0;
        csrValue_o <= 0;
        writeLen_o <= 0;
        pc_mret_o <= 0;
    end
    else begin
        aluRes_o <= aluRes;
        //$display(aluRes);
        memoryReadWen_o <= memoryReadWen;
        readNum_o <= readNum;
        pc_o <= pc;
        imm_o <= imm;
        wd_sel_o <= wd_sel;
        rs1_o <= rs1;
        rs2_o <= rs2;
        memoryWriteMask_o <= memoryWriteMask;
        sext_o <= sext;
        writeRD_o <= writeRD;
        rwaddr_o <= rwaddr;
        jal_o <= jal;
        jalr_o <= jalr;
        branch_o <= branch;
        csrWen_o <= csrWen;
        csrValue_o <= csrValue;
        writeLen_o <= writeLen;
        pc_mret_o <= pc_mret;
    end
 
end
endmodule

module ysyx_041207_flush (
    input me_jal,
    input me_jalr,
    input ex_pc_panic,
    input me_branch,
    input [63:0] me_aluRes,
    input clint_i,
    input mret,
    input clear_afterID,
    output wire  flush
);
//always @(posedge clk) begin
    // 下一个周期需要冲刷掉中间的全部指令
    assign flush = me_jal || me_jalr || (me_branch && me_aluRes == 0) || ex_pc_panic || clint_i || (mret && clear_afterID);
    //if (flush) begin
    //    $display("flush = %d", flush);
    //end
//end
endmodule

module ysyx_041207_GetInstType (
    input [6:0] opCode,
    output [2:0] instType
);
assign instType = (opCode == 7'b0110011) ? `R_Type : 
    (
    (opCode == 7'b0010011 || opCode == 7'b0000011 || opCode == 7'b1100111 || opCode == 7'b1110011 || opCode == 7'b0011011) ? `I_Type : 
    (opCode == 7'b0100011 ? `S_Type : 
    (opCode == 7'b1100011 ? `B_Type : 
    (opCode == 7'b1101111 ? `J_Type : 
    ((opCode == 7'b0110111 || opCode == 7'b0010111) ? `U_Type : 3'b0
    )))));

endmodule

module ysyx_041207_IF (
    input clk,
    input rst,
    input flush,
    input pc_delay,
    input me_jal,
    input me_jalr,
    input me_branch,
    input pc_panic,
    input [63:0] me_aluRes,
    input [63:0] csr_mtvec,
    input [63:0] csr_mepc,
    input [63:0] me_pc,
    input [63:0] me_imm,
    input [63:1] me_r1data,
    output reg [31:0] inst_o,
    output reg [63:0] pc_o,
    output reg rx_r_valid_i,
    input      rx_r_ready_o,
    input [63:0] rx_data_read_o,
    output reg [63:0] rx_r_addr_i,
    output [2:0] rx_r_size_i,
    input rx_data_valid,
    output reg rx_data_ready,
    input wire mret
);
reg [63:0] pc;
wire [63:0] pcPlus4 = pc + 64'h4;
assign rx_r_size_i = 3'h2;  // 读取2^2=4字节
// ysyx_041207_read_mem readInst(pc, 1'b1, rawData);
// assign inst = rawData [31:0];  // 这里可能有BUG
reg axi_free;
wire [63:1] addRes;
assign addRes = me_r1data[63:1] + me_imm[63:1];
always @(posedge clk) begin
    if (~rst) begin
    // 开始读入指令
    //$display("pc :%x", pc);
    if (rx_data_valid && rx_data_ready) begin
        // 当前pc的指令已经取完了 并且读的是当前应该读的pc(因为中途可能发生了跳转)
        //$display("finish read %x", rx_r_addr_i);
        rx_data_ready <= 0;
        if (rx_r_addr_i == pc && ~flush) begin
            // 当前读的pc是正确的(要顺便判断当前pc是否会跳转)，那就传递下去
            inst_o <= (pc[2:0] == 3'h4) ? rx_data_read_o[63:32] : rx_data_read_o[31:0];
            //$display("pc:%x %x", pc, (pc[2:0] == 3'h4) ? rx_data_read_o[63:32] : rx_data_read_o[31:0]);
            pc_o <= pc;
            axi_free <= 1;  // axi已经释放
        end else begin
            // 说明发生了跳转，刚刚的读的作废
            inst_o <= 0;
            pc_o <= 0;
            axi_free <= 0;
            //$display("pread:%x", pc);
            //if (pc >= 64'h0x80000000) begin
                //$display("start to read %x", pc);
            //end
            rx_r_addr_i <= pc;
            pc <= pc;
            rx_r_valid_i <= 1;
        end
    end else if (~pc_delay) begin   // 已经传递下去了
        inst_o <= 0;
        pc_o <= 0;
        //$display(axi_free);
        if (axi_free) begin // 那就直接进行+4
            rx_r_addr_i <= pcPlus4;
            //$display("start to read %x", pcPlus4);
            pc <= pcPlus4;
            rx_r_valid_i <= 1;
            axi_free <= 0;
        end
    end
    end
end
always @(posedge clk) begin
    if (~rst) begin
    if (rx_r_valid_i && rx_r_ready_o) begin // axi模块已经接收到了地址
        rx_r_valid_i <= 0;
        rx_data_ready <= 1; // 准备好接收数据
        //$display("recieve address");
    end
    end
end

always @(posedge clk) begin
    if (rst) begin
        `ifdef RLocal
        pc <= 64'h80000000 - 64'h4;
        `endif
        `ifndef RLocal
        pc <= 64'h2FFFFFFC;//64'h0x30000000- 64'h4;
        `endif
        rx_r_addr_i <= 64'h0;
        rx_data_ready <= 0;
        rx_r_valid_i <= 0;
        axi_free <= 1;
        inst_o <= 0;
        pc_o <= 0;
    end
    else begin
        if (pc_panic) begin
            //$display("pc_panic %x", csr_mtvec);
            pc <= csr_mtvec;
        end else if (mret) begin
            //$display("mret %x", csr_mepc);
            pc <= csr_mepc;
        end else if (me_jal || (me_branch && me_aluRes == 0)) begin
            //$display("catch jal... %x %x", me_pc, me_imm);
            pc <= me_pc + me_imm;
        end
        else if (me_jalr) begin // jalr要求最后一位置0
            //(ex_r1data + ex_imm)
            //$display("catch jalr...");
            //$display("jalr %x", {addRes[63:1], 1'b0});
            pc <= {addRes[63:1], 1'b0};
        end
    end
end
endmodule

// 所有写入数据都是从rs2中而来
module ysyx_041207_Memory (
    input clk,
    input rst,
    input clint_ready,
    input readWen,
    input [63:0] addr,
    input [63:0] rs2,
    input [7:0]  wmask,
    input [2:0]  w_len,
    input sext,
    input [2:0] readNum,
    output reg [63:0] dout,
    input  [63:0] me_pc,
    input  [63:0] me_imm,
    input  [2:0] me_writeBackDataSelect,
    input  me_writeRD,
    input  [4:0] me_rwaddr,
    input  me_csrWen,
    input  [63:0] me_csrValue,
    // axi 写
    output reg                  w_valid_i,
	  input                       w_ready_o,
    output reg [63:0]           w_data_i,
    output  reg [63:0]          w_addr_i,
    output reg [7:0]            w_mask_i,
    output reg [2:0]            w_size_i,
    input  wire                 tw_valid_o,
    output  reg                 w_ready_i,
    // axi 读
    output reg rx_r_valid_i,
    input      rx_r_ready_o,
    input [63:0] rx_data_read_o,
    output reg [63:0] rx_r_addr_i,
    output [2:0] rx_r_size_i,
    input rx_data_valid,
    output reg rx_data_ready,
    output reg me_wait_for_axi,
    output [63:0] mtimecmp_o,
    output [63:0] mtime_o,

    output reg [63:0] me_aluRes_o,
    output reg [63:0] me_pc_o,
    output reg [63:0] me_imm_o,
    output reg [2:0] me_writeBackDataSelect_o,
    output reg me_writeRD_o,
    output reg [4:0] me_rwaddr_o,
    output reg me_csrWen_o,
    output reg [63:0] me_csrValue_o

    

);

    
reg [63:0] tme_aluRes_o;
reg [63:0] tme_pc_o;
reg [63:0] tme_imm_o;
reg [2:0] tme_writeBackDataSelect_o;
reg tme_writeRD_o;
reg [4:0] tme_rwaddr_o;
reg tme_csrWen_o;
reg [63:0] tme_csrValue_o;
reg busy;
reg [2:0] t_readNum;
reg t_sext;
assign rx_r_size_i = readNum;

wire [63:0] trueData = 
((rx_r_addr_i[2:0] == 3'h0) ? rx_data_read_o :
((rx_r_addr_i[2:0] == 3'h1) ? (rx_data_read_o >>  8): 
((rx_r_addr_i[2:0] == 3'h2) ? (rx_data_read_o >> 16):
((rx_r_addr_i[2:0] == 3'h3) ? (rx_data_read_o >> 24):
((rx_r_addr_i[2:0] == 3'h4) ? (rx_data_read_o >> 32):
((rx_r_addr_i[2:0] == 3'h5) ? (rx_data_read_o >> 40):
((rx_r_addr_i[2:0] == 3'h6) ? (rx_data_read_o >> 48):
((rx_r_addr_i[2:0] == 3'h7) ? (rx_data_read_o >> 56):
0
))))))));
reg [63:0] mtimecmp, mtime;
assign mtimecmp_o = mtimecmp;
assign mtime_o = mtime;
wire [63:0] alignedAddr = {addr[63:3], 3'b0};
wire [7:0] nmask = (wmask << addr[2:0]);
wire [7:0] mmask = (wmask << addr[2:0]);
wire [63:0] realData = rs2 << ({3'b0, addr[2:0]} << 3);
wire [63:0] tcmp_trueData = 
((addr[2:0] == 3'h0) ? mtimecmp :
((addr[2:0] == 3'h1) ? (mtimecmp >>  8): 
((addr[2:0] == 3'h2) ? (mtimecmp >> 16):
((addr[2:0] == 3'h3) ? (mtimecmp >> 24):
((addr[2:0] == 3'h4) ? (mtimecmp >> 32):
((addr[2:0] == 3'h5) ? (mtimecmp >> 40):
((addr[2:0] == 3'h6) ? (mtimecmp >> 48):
((addr[2:0] == 3'h7) ? (mtimecmp >> 56):
0
))))))));
wire [63:0] t_trueData = 
((addr[2:0] == 3'h0) ? mtime :
((addr[2:0] == 3'h1) ? (mtime >>  8): 
((addr[2:0] == 3'h2) ? (mtime >> 16):
((addr[2:0] == 3'h3) ? (mtime >> 24):
((addr[2:0] == 3'h4) ? (mtime >> 32):
((addr[2:0] == 3'h5) ? (mtime >> 40):
((addr[2:0] == 3'h6) ? (mtime >> 48):
((addr[2:0] == 3'h7) ? (mtime >> 56):
0
))))))));
`define finish me_aluRes_o <= addr;\
    me_pc_o <= me_pc;\
    me_imm_o <= me_imm;\
    me_writeBackDataSelect_o <= me_writeBackDataSelect;\
    me_writeRD_o <= me_writeRD;\
    me_rwaddr_o <= me_rwaddr;\
    me_csrWen_o <= me_csrWen;\
    me_csrValue_o <= me_csrValue;
`define finish1 me_aluRes_o <= tme_aluRes_o;\
    me_pc_o <= tme_pc_o;\
    me_imm_o <= tme_imm_o;\
    me_writeBackDataSelect_o <= tme_writeBackDataSelect_o;\
    me_writeRD_o <= tme_writeRD_o;\
    me_rwaddr_o <= tme_rwaddr_o;\
    me_csrWen_o <= tme_csrWen_o;\
    me_csrValue_o <= tme_csrValue_o;
always @(posedge clk) begin
  if (~(alignedAddr == `MTIME_ADDRESS && wmask != 8'b0)) begin
    mtime <= mtime + 64'h1;
    //$display("mtime:%x mcmp:%x", mtime, mtimecmp);
  end
  if (rst) begin
    busy <= 0;
    w_valid_i <= 0;
    rx_r_valid_i <= 0;
    me_wait_for_axi <= 0;
    mtimecmp <= 0;
    mtime <= 0;
    me_aluRes_o <= 0;
    me_pc_o <= 0;
    me_imm_o <= 0;
    me_writeBackDataSelect_o <= 0;
    me_writeRD_o <= 0;
    me_rwaddr_o <= 0;
    me_csrWen_o <= 0;
    me_csrValue_o <= 0;
    w_ready_i <= 0;
    rx_data_ready <= 0;
  end else begin
  // 写入
   if (wmask != 8'b0 && ~busy && ~clint_ready) begin  // 说明要进入数据写入，可以开始卡住流水线了
    if (alignedAddr == `MTIMECMP_ADDRESS) begin  // mtimecmp
      for (integer i = 0;i < 8;i ++) begin
        if (nmask[i]) begin
          mtimecmp [(i * 8)+: 8] <= realData [(i * 8)+: 8];
        end
      end
      //$display("write tcmp:%x %x %x", rs2, mtimecmp, nmask);
      me_wait_for_axi <= 0;
      `finish
    end else if (alignedAddr == `MTIME_ADDRESS) begin
      for (integer i = 0;i < 8;i ++) begin
        if (mmask[i]) begin
          mtime [(i * 8)+: 8] <= realData [(i * 8)+: 8];
        end
      end
      me_wait_for_axi <= 0;
      `finish
    end else begin
      busy <= 1;
      w_valid_i <= 1;
      w_addr_i <= addr;
      w_size_i <= w_len;
      w_mask_i <= nmask;
      w_data_i <= realData;
      me_wait_for_axi <= 1;

      me_aluRes_o <= 0;
      me_pc_o <= 0;
      me_imm_o <= 0;
      me_writeBackDataSelect_o <= 0;
      me_writeRD_o <= 0;
      me_rwaddr_o <= 0;
      me_csrWen_o <= 0;
      me_csrValue_o <= 0;

      tme_aluRes_o <= addr;
      tme_pc_o <= me_pc;
      tme_imm_o <= me_imm;
      tme_writeBackDataSelect_o <= me_writeBackDataSelect;
      tme_writeRD_o <= me_writeRD;
      tme_rwaddr_o <= me_rwaddr;
      tme_csrWen_o <= me_csrWen;
      tme_csrValue_o <= me_csrValue;
    end
  end
  if (w_valid_i && w_ready_o) begin
    w_valid_i <= 0; // axi模块已经收到写入请求
    w_ready_i <= 1;
  end
  if (tw_valid_o && w_ready_i) begin  // 已经完成写入
    //$display("write %x %x %b", w_addr_i, w_data_i, w_mask_i);
    w_ready_i <= 0;
    me_wait_for_axi <= 0;
    busy <= 0;
    `finish1
  end
  // 读取
  if (readWen && ~busy && ~clint_ready) begin
    if (addr == `MTIMECMP_ADDRESS) begin
      //$display("read tcmp:%x", mtimecmp);
      `finish
      if (sext) begin
      // 需要做符号扩展
      dout <= (readNum == 3'h0) ? `SEXT(tcmp_trueData, 64, 8)
      : ((readNum == 3'h1) ? `SEXT(tcmp_trueData, 64, 16)
      : ((readNum == 3'h2) ? `SEXT(tcmp_trueData, 64, 32)
      : ((readNum == 3'h3) ? `SEXT(tcmp_trueData, 64, 64) : 0
      )));
      end
      else begin
      dout <= (readNum == 3'h0) ? `NSEXT(tcmp_trueData, 64, 8)
      : ((readNum == 3'h1) ? `NSEXT(tcmp_trueData, 64, 16)
      : ((readNum == 3'h2) ? `NSEXT(tcmp_trueData, 64, 32)
      : ((readNum == 3'h3) ? `NSEXT(tcmp_trueData, 64, 64) : 0
      )));
      end
      me_wait_for_axi <= 0;
    end
    else if (addr == `MTIME_ADDRESS) begin
      `finish
      if (sext) begin
      // 需要做符号扩展
      dout <= (readNum == 3'h0) ? `SEXT(t_trueData, 64, 8)
      : ((readNum == 3'h1) ? `SEXT(t_trueData, 64, 16)
      : ((readNum == 3'h2) ? `SEXT(t_trueData, 64, 32)
      : ((readNum == 3'h3) ? `SEXT(t_trueData, 64, 64) : 0
      )));
      end
      else begin
        dout <= (readNum == 3'h0) ? `NSEXT(t_trueData, 64, 8)
        : ((readNum == 3'h1) ? `NSEXT(t_trueData, 64, 16)
        : ((readNum == 3'h2) ? `NSEXT(t_trueData, 64, 32)
        : ((readNum == 3'h3) ? `NSEXT(t_trueData, 64, 64) : 0
        )));
      end
      me_wait_for_axi <= 0;
    end
    else begin 
      rx_r_valid_i <= 1;
      //$display("%x:read addr:%x %x", me_pc, addr, readNum);
      rx_r_addr_i <= addr;
      me_wait_for_axi <= 1;
      busy <= 1;
      t_readNum <= readNum;
      t_sext <= sext;
      me_aluRes_o <= 0;
      me_pc_o <= 0;
      me_imm_o <= 0;
      me_writeBackDataSelect_o <= 0;
      me_writeRD_o <= 0;
      me_rwaddr_o <= 0;
      me_csrWen_o <= 0;
      me_csrValue_o <= 0;

      tme_aluRes_o <= addr;
      tme_pc_o <= me_pc;
      tme_imm_o <= me_imm;
      tme_writeBackDataSelect_o <= me_writeBackDataSelect;
      tme_writeRD_o <= me_writeRD;
      tme_rwaddr_o <= me_rwaddr;
      tme_csrWen_o <= me_csrWen;
      tme_csrValue_o <= me_csrValue;
    end
  end
  if (rx_r_valid_i && rx_r_ready_o) begin // axi模块已经收到读取请求
    rx_r_valid_i <= 0;
    rx_data_ready <= 1;
  end
  if (rx_data_valid && rx_data_ready) begin  // 收到axi模块返回的数据
    rx_data_ready <= 0;
    busy <= 0;
    me_wait_for_axi <= 0;
    `finish1
    //$display("finish read:%x", rx_r_addr_i);
    if (t_sext) begin
      // 需要做符号扩展
      dout <= (t_readNum == 3'h0) ? `SEXT(trueData, 64, 8)
      : ((t_readNum == 3'h1) ? `SEXT(trueData, 64, 16)
      : ((t_readNum == 3'h2) ? `SEXT(trueData, 64, 32)
      : ((t_readNum == 3'h3) ? `SEXT(trueData, 64, 64) : 0
      )));
    end
    else begin
      dout <= (t_readNum == 3'h0) ? `NSEXT(trueData, 64, 8)
      : ((t_readNum == 3'h1) ? `NSEXT(trueData, 64, 16)
      : ((t_readNum == 3'h2) ? `NSEXT(trueData, 64, 32)
      : ((t_readNum == 3'h3) ? `NSEXT(trueData, 64, 64) : 0
      )));
    end
  end
  end
  if (~readWen && wmask == 0 && ~busy) begin
    if (~clint_ready) begin
      `finish
      dout <= 0;
    end else begin  // 不再接收新的memory请求
      me_aluRes_o <= 0;
      me_pc_o <= 0;
      me_imm_o <= 0;
      me_writeBackDataSelect_o <= 0;
      me_writeRD_o <= 0;
      me_rwaddr_o <= 0;
      me_csrWen_o <= 0;
      me_csrValue_o <= 0;
    end
  end
end
endmodule

module ysyx_041207_mul (
    input clk,
    input rst,
    input mul_valid,
    input flush,
    input [63:0] multiplicand,  // 被乘数
    input [63:0] multiplier,    // 乘数
    output reg out_valid,
    output reg [63:0] mul_res_o
);
reg mul_ready;
reg [63:0] l_multiplicand, l_multiplier;
reg [63:0] mul_res;
reg [7:0] count;
always @(posedge clk) begin
    if (rst) begin
        mul_res <= 0;
        count <= 0;
        mul_ready <= 1;
        out_valid <= 0;
        mul_res_o <= 0;
    end else begin
        if (mul_valid && (mul_ready || flush)) begin
            //$display("mul %x %x", multiplicand, multiplier);
            l_multiplicand <= multiplicand;
            l_multiplier <= multiplier;
            count <= 0;
            mul_ready <= 0;
            mul_res <= 0;
        end
        if (~flush && ~mul_ready && count != 8'h40) begin
            mul_res <= mul_res + ((l_multiplier[0]) ? l_multiplicand : 0);
            l_multiplicand <= l_multiplicand << 1;
            l_multiplier <= l_multiplier >> 1;
            count <= count + 1;
        end
        if (~flush && ~mul_ready && count == 8'h40 && ~out_valid) begin
            //mul_res <= mul_res + ((l_multiplier[0]) ? l_multiplicand : 0);
            //mul_res <= multiplicand * multiplier;
            //$display("mul %x %x %x %x", multiplicand, multiplier, mul_res, multiplicand * multiplier);
            if (mul_res != multiplicand * multiplier) begin
                //$display("mul %x %x %x %x", multiplicand, multiplier, mul_res, multiplicand * multiplier);
            end
            out_valid <= 1;
            count <= 0;
            mul_res_o <= mul_res;
            //mul_res_o <= multiplicand * multiplier;
        end
        if (out_valid) begin
            mul_ready <= 1;
            out_valid <= 0;
        end
    end
end
endmodule

//import "DPI-C" function void set_gpr_ptr(input logic [63:0] a []);
module ysyx_041207_RegisterFile #(REGISTER_NUM = 2, ADDR_WIDTH = 1, DATA_WIDTH = 1) (
  input clk,
  input rst,
  input [DATA_WIDTH-1:0] wdata,
  input [ADDR_WIDTH-1:0] waddr,
  input [ADDR_WIDTH-1:0] r1addr,
  output [DATA_WIDTH-1:0] r1data,
  input [ADDR_WIDTH-1:0] r2addr,
  output [DATA_WIDTH-1:0] r2data,
  input wen
);
  
  //initial set_gpr_ptr(rf);  // rf为通用寄存器的二维数组变量
  reg [DATA_WIDTH-1:0] rf [REGISTER_NUM-1:0];
  assign r1data = rf[r1addr];
  assign r2data = rf[r2addr];
  always @(posedge clk) begin
    if (rst) begin
      for (integer i = 0;i < REGISTER_NUM;i ++) begin
        rf[i] <= 0;
      end
    end else begin
    if (wen && waddr != 0) begin
       rf[waddr] <= wdata;
    end
    end
    if (r1addr == 5'h2 || r2addr == 5'h2) begin
      //$display("read sp:%x", rf[5'h2]);
    end
    //$display("a1:%b", rf [1]);
  end
endmodule
// 0x341 mepc
// 0x342 mcause
// 0x305 mtvec
// 0x300 mstatus
module ysyx_041207_csrRegister (
  input clk,
  input rst,
  input [63:0] ex_pc_o,
  input pc_mret,
  input wen,
  input panic,
  input [11:0] readAddress,
  input [11:0] writeAddress,
  input [63:0] writeValue,
  input wMcause,
  input [63:0] mcause_v,
  input [63:0] mtime_v,
  input [63:0] mtimecmp_v,
  output [63:0] mtvec_o,
  output [63:0] mepc_o,
  output [63:0] readData,
  output wire clint_i,
  output wire clint_ready // 只等待memory模块有指令进入，进而截取pc了
);
reg [63:0] mepc, mcause, mtvec, mstatus, mie, mip;
//assign clint_i = 0;
assign clint_ready = (mtime_v >= mtimecmp_v) && mstatus[3] && mie [7];
assign clint_i = (mtime_v >= mtimecmp_v) && mstatus[3] && mie [7] && (ex_pc_o != 0);  // me_pc不为0,可以保证一定可以获取到位置

assign mtvec_o = mtvec;
assign mepc_o = mepc;
always @(posedge clk) begin
  if (clint_i) begin
    //$display("clint %x %x", mtime_v, mtimecmp_v);
  end
  if (rst) begin
    mtvec <= 0;
  end 
  else if (writeAddress == `CSR_MTVEC_ADDRESS && wen) begin
    //$display("write mtvec %x", writeValue);
    mtvec <= writeValue;
  end
end
always @(posedge clk) begin
  if (rst) begin
    mcause <= 0;
  end 
  else if (writeAddress == `CSR_MCAUSE_ADDRESS && wen) begin
    mcause <= writeValue;
  end else if (wMcause) begin
    mcause <= mcause_v;
  end else if (clint_i) begin
    mcause <= 64'h8000000000000007;
  end
end
always @(posedge clk) begin
  if (rst) begin
    mepc <= 0;
  end 
  else if (writeAddress == `CSR_MEPC_ADDRESS && wen) begin
    mepc <= writeValue;
  end else if (panic) begin
    //$display("panic pc:%x", me_pc);
    mepc <= ex_pc_o;  // 因为ex的指令会被冲刷，所以实际上下一条指令是ex_pc
  end if (clint_i) begin
    //$display("write mepc:%x", me_pc);
    mepc <= ex_pc_o;
  end
end
always @(posedge clk) begin
  if (rst) begin
    mstatus <= 0;
  end 
  else if (writeAddress == `CSR_MSTATUS_ADDRESS && wen) begin
    //$display("write mstatus %x", writeValue);
    mstatus <= writeValue;
  end else if (panic || clint_i) begin
    //mstatus <= mstatus_v;
    // 表明异常开始 按照流程进行设置
    //mcause <= mcause []
    // 将pie位存到mpie,且将pie位置为0
    mstatus <= {mstatus[63:8], mstatus[3], mstatus[6:4], 1'b0, mstatus[2:0]};
  end else if (pc_mret) begin  //恢复
    //$display("mepc:%x", mepc);
    mstatus <= {mstatus[63:8], 1'b1, mstatus[6:4], mstatus[7], mstatus[2:0]};
  end
end
always @(posedge clk) begin
  if (rst) begin
    mie <= 0;
  end else if (writeAddress == `CSR_MIE_ADDRESS && wen) begin
    mie <= writeValue;
  end
end
always @(posedge clk) begin
  if ((mtime_v >= mtimecmp_v) && mstatus[3] && mie [7]) begin

  end
  if (rst) begin
    mip <= 0;
  end else if (writeAddress == `CSR_MIP_ADDRESS && wen) begin
    mip <= writeValue;
  end
  if (mtime_v >= mtimecmp_v) begin
    mip [7] <= 1;  // 设置mtip
  end
end
assign readData = (readAddress == `CSR_MCAUSE_ADDRESS) ? mcause :
                  (readAddress == `CSR_MEPC_ADDRESS) ? mepc :
                  (readAddress == `CSR_MSTATUS_ADDRESS) ? mstatus :
                  (readAddress == `CSR_MTVEC_ADDRESS) ? mtvec :
                  (readAddress == `CSR_MIE_ADDRESS) ? mie :
                  (readAddress == `CSR_MIP_ADDRESS) ? mip :
                  0;
endmodule

module ysyx_041207_SEXT(
    input [31:7]  instr,
    input [ 2:0] sext_op ,
    output reg  [63:0]  imm
    );
    always @(*)
    begin
            case(sext_op)
            `I_Type:
                imm = {{(53){instr[31]}}, instr[30:20]};
            `S_Type:
                imm = {{(53){instr[31]}}, instr[30:25], instr[11:7]};
            `B_Type: begin
                imm = {{(52){instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0};
            end
            `U_Type:
                imm = {{(33){instr[31]}}, instr[30:12], 12'b0};
            `J_Type:
                imm = {{(44){instr[31]}}, instr[19:12], instr[20], instr[30:21], 1'b0};
            default:         imm = 64'b0;
            endcase
            //$display("imm:%x", imm);
    end
endmodule

/*
   _  __                       ____  _________ ______   _    __   ____                                           
  | |/ /_  ______ _____       / __ \/  _/ ___// ____/  | |  / /  / __ \_________  ________  ______________  _____
  |   / / / / __ `/ __ \     / /_/ // / \__ \/ /  _____| | / /  / /_/ / ___/ __ \/ ___/ _ \/ ___/ ___/ __ \/ ___/
 /   / /_/ / /_/ / / / /    / _, _// / ___/ / /__/_____/ |/ /  / ____/ /  / /_/ / /__/  __(__  |__  ) /_/ / /    
/_/|_\__,_/\__,_/_/ /_(_)  /_/ |_/___//____/\____/     |___/  /_/   /_/   \____/\___/\___/____/____/\____/_/        
*/
module ysyx_041207 (
  input   clock ,
  input   io_interrupt ,
  input   io_master_arready ,
  input   io_master_awready ,
  input   io_master_bvalid ,
  input   io_master_rlast ,
  input   io_master_rvalid ,
  input   io_master_wready ,
  input   io_slave_arvalid ,
  input   io_slave_awvalid ,
  input   io_slave_bready ,
  input   io_slave_rready ,
  input   io_slave_wlast ,
  input   io_slave_wvalid ,
  input   reset ,
  input [1:0]   io_master_bresp ,
  input [1:0]   io_master_rresp ,
  input [1:0]   io_slave_arburst ,
  input [1:0]   io_slave_awburst ,
  input [2:0]   io_slave_arsize ,
  input [2:0]   io_slave_awsize ,
  input [31:0]   io_slave_araddr ,
  input [31:0]   io_slave_awaddr ,
  input [3:0]   io_master_bid ,
  input [3:0]   io_master_rid ,
  input [3:0]   io_slave_arid ,
  input [3:0]   io_slave_awid ,
  input [63:0]   io_master_rdata ,
  input [63:0]   io_slave_wdata ,
  input [7:0]   io_slave_arlen ,
  input [7:0]   io_slave_awlen ,
  input [7:0]   io_slave_wstrb ,
  output   io_master_arvalid ,
  output   io_master_awvalid ,
  output   io_master_bready ,
  output   io_master_rready ,
  output   io_master_wlast ,
  output   io_master_wvalid ,
  output   io_slave_arready ,
  output   io_slave_awready ,
  output   io_slave_bvalid ,
  output   io_slave_rlast ,
  output   io_slave_rvalid ,
  output   io_slave_wready ,
  `ifndef RLocal
  input [127:0]   io_sram0_rdata ,
  input [127:0]   io_sram1_rdata ,
  input [127:0]   io_sram2_rdata ,
  input [127:0]   io_sram3_rdata ,
  input [127:0]   io_sram4_rdata ,
  input [127:0]   io_sram5_rdata ,
  input [127:0]   io_sram6_rdata ,
  input [127:0]   io_sram7_rdata ,
  output   io_sram0_cen ,
  output   io_sram0_wen ,
  output   io_sram1_cen ,
  output   io_sram1_wen ,
  output   io_sram2_cen ,
  output   io_sram2_wen ,
  output   io_sram3_cen ,
  output   io_sram3_wen ,
  output   io_sram4_cen ,
  output   io_sram4_wen ,
  output   io_sram5_cen ,
  output   io_sram5_wen ,
  output   io_sram6_cen ,
  output   io_sram6_wen ,
  output   io_sram7_cen ,
  output   io_sram7_wen ,
  output [127:0]   io_sram0_wdata ,
  output [127:0]   io_sram0_wmask ,
  output [127:0]   io_sram1_wdata ,
  output [127:0]   io_sram1_wmask ,
  output [127:0]   io_sram2_wdata ,
  output [127:0]   io_sram2_wmask ,
  output [127:0]   io_sram3_wdata ,
  output [127:0]   io_sram3_wmask ,
  output [127:0]   io_sram4_wdata ,
  output [127:0]   io_sram4_wmask ,
  output [127:0]   io_sram5_wdata ,
  output [127:0]   io_sram5_wmask ,
  output [127:0]   io_sram6_wdata ,
  output [127:0]   io_sram6_wmask ,
  output [127:0]   io_sram7_wdata ,
  output [127:0]   io_sram7_wmask ,
  output [5:0]   io_sram0_addr ,
  output [5:0]   io_sram1_addr ,
  output [5:0]   io_sram2_addr ,
  output [5:0]   io_sram3_addr ,
  output [5:0]   io_sram4_addr ,
  output [5:0]   io_sram5_addr ,
  output [5:0]   io_sram6_addr ,
  output [5:0]   io_sram7_addr ,
  `endif
  output [1:0]   io_master_arburst ,
  output [1:0]   io_master_awburst ,
  output [1:0]   io_slave_bresp ,
  output [1:0]   io_slave_rresp ,
  output [2:0]   io_master_arsize ,
  output [2:0]   io_master_awsize ,
  output [31:0]   io_master_araddr ,
  output [31:0]   io_master_awaddr ,
  output [3:0]   io_master_arid ,
  output [3:0]   io_master_awid ,
  output [3:0]   io_slave_bid ,
  output [3:0]   io_slave_rid ,
  output [63:0]   io_master_wdata ,
  output [63:0]   io_slave_rdata ,
  output [7:0]   io_master_arlen ,
  output [7:0]   io_master_awlen ,
  output [7:0]   io_master_wstrb
);
  assign   io_slave_arready = 0;
  assign   io_slave_awready = 0;
  assign   io_slave_bvalid = 0;
  assign   io_slave_rlast = 0;
  assign   io_slave_rvalid = 0;
  assign   io_slave_wready = 0;
  assign io_slave_bresp = 0;
  assign io_slave_rid = 0;
  assign io_slave_rdata = 0;
  `ifndef RLocal
  assign io_sram4_wmask = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;;
  assign io_sram5_wmask = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;;
  assign io_sram6_wmask = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;;
  assign io_sram7_wmask = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;;
  assign   io_sram4_cen = 0;
  assign   io_sram4_wen = 0;
  assign   io_sram5_cen = 0;
  assign   io_sram5_wen = 0;
  assign   io_sram6_cen = 0;
  assign   io_sram6_wen = 0;
  assign   io_sram7_cen = 0;
  assign   io_sram7_wen = 0;
  assign   io_sram4_wdata = 0;
  assign   io_sram5_wdata = 0;
  assign   io_sram6_wdata = 0;
  assign   io_sram7_wdata = 0;
  assign   io_sram4_addr = 0;
  assign   io_sram5_addr = 0;
  assign   io_sram6_addr = 0;
  assign   io_sram7_addr = 0;
  `endif
  `ifdef RLocal
wire [127:0] io_sram0_rdata ;
wire [127:0] io_sram1_rdata ;
wire [127:0] io_sram2_rdata ;
wire [127:0] io_sram3_rdata ;
wire io_sram0_cen ;
wire io_sram0_wen ;
wire io_sram1_cen ;
wire io_sram1_wen ;
wire io_sram2_cen ;
wire io_sram2_wen ;
wire io_sram3_cen ;
wire io_sram3_wen ;
wire [127:0] io_sram0_wdata ;
wire [127:0] io_sram0_wmask ;
wire [127:0] io_sram1_wdata ;
wire [127:0] io_sram1_wmask ;
wire [127:0] io_sram2_wdata ;
wire [127:0] io_sram2_wmask ;
wire [127:0] io_sram3_wdata ;
wire [127:0] io_sram3_wmask ;
wire [5:0] io_sram0_addr ;
wire [5:0] io_sram1_addr ;
wire [5:0] io_sram2_addr ;
wire [5:0] io_sram3_addr ;
 rsram rsram0(
    clk,
    io_sram0_cen,
    io_sram0_wen,
    io_sram0_wmask,
    io_sram0_addr,
    io_sram0_wdata,
    io_sram0_rdata
);
rsram rsram1(
    clk,
    io_sram1_cen,
    io_sram1_wen,
    io_sram1_wmask,
    io_sram1_addr,
    io_sram1_wdata,
    io_sram1_rdata
);
rsram rsram2(
    clk,
    io_sram2_cen,
    io_sram2_wen,
    io_sram2_wmask,
    io_sram2_addr,
    io_sram2_wdata,
    io_sram2_rdata
);
rsram rsram3(
    clk,
    io_sram3_cen,
    io_sram3_wen,
    io_sram3_wmask,
    io_sram3_addr,
    io_sram3_wdata,
    io_sram3_rdata
);
  `endif
assign io_slave_awready = 0;
assign io_slave_wready = 0;
assign io_slave_bvalid		 = 0;	
assign	io_slave_bid			 = 0;
assign	io_slave_bresp		 = 0;	
assign io_slave_arready	 = 0;
assign io_slave_rvalid			 = 0;
assign	io_slave_rid			 = 0;
assign	io_slave_rresp		 = 0;	
assign	io_slave_rdata		 = 0;	
assign	io_slave_rlast = 0;
wire flush;
wire me_wait_for_axi;
// mem的axi读信号
wire [63:0] csr_mtvec, csr_mepc, ex_csr_readData;
wire clint_i;
wire mem_r_valid_i, mem_r_ready_o;
wire [63:0] mem_data_read_o;
wire [63:0] mem_r_addr_i;
wire [2:0] mem_r_size_i;
wire [63:0] mtimecmp, mtime;
wire mem_data_valid, mem_data_ready;
wire [63:0] me_aluRes_o, me_pc_o, me_imm_o, me_csrValue_o;
wire [2:0] me_writeBackDataSelect_o;
wire me_writeRD_o;
wire [4:0] me_rwaddr_o;
wire me_csrWen_o;
wire clint_ready;
wire [31:0] if_inst;
wire [63:0] if_pc;
wire clear_afterID;
wire [2:0] id_csrOrder;
// axi 读信号
wire rx_r_valid_i, rx_r_ready_o;
wire [63:0] rx_data_read_o;
wire [63:0] rx_r_addr_i;
wire [2:0] rx_r_size_i;
wire rx_data_valid, rx_data_ready;
// axi 写信号
wire rx_w_valid_i, rx_w_ready_o;
wire [63:0] rx_data_write_i;
wire [63:0] rx_w_addr_i;
wire [7:0] rx_w_mask_i;
wire rx_w_ready_i, rx_w_valid_o;
wire [2:0] rx_w_size_i;
wire  bubble;
wire [4:0] id_aluOperate;
wire [1:0] id_sel_a, id_sel_b;
wire [7:0] id_memoryWriteMask;
wire id_writeRD;
wire id_jalr, id_jal;
wire[2:0] id_writeBackDataSelect;
wire id_memoryReadWen;
wire [63:0] me_memoryReadData;
wire id_sext;
wire [2:0] id_readNum;
wire id_rs1to32, id_wMcause, id_pc_panic, id_pc_mret, id_csrWen, id_dbranch;
wire [63:0] id_imm, id_mcause;
wire [4:0] id_r1addr, id_r2addr, id_rwaddr;
wire [63:0] id_pc_o;
wire ex_alu_wait;
wire ex_memoryReadWen_o;
wire [2:0] ex_readNum_o;
wire [63:0] ex_pc_o;
wire [63:0] ex_imm_o;
wire [2:0] ex_writeBackDataSelect_o;
wire [63:0] wb_writeBackData;
wire [62:0] ex_forward_rs1_o;
wire [63:0] ex_forward_rs2_o;
wire [7:0] ex_memoryWriteMask_o;
wire ex_sext_o;
wire ex_writeRD_o;
wire [4:0] ex_rwaddr_o;
wire ex_jal_o;
wire ex_jalr_o;
wire ex_dbranch_o;
wire ex_csrWen_o;
wire [63:0] ex_csr_readData_o;
wire [2:0] ex_writeLen_o;
wire ex_pc_mret_o;
wire ex_pc_panic_o;
wire [63:0] ex_r1data, ex_r2data;

wire [2:0] id_writeLen;
wire [63:0] ex_aluRes;
wire [63:0] ex_forward_rs1, ex_forward_rs2;
wire id_afterIDClear = (ex_pc_o == 0 && me_pc_o == 0 && ~me_wait_for_axi && ~ex_alu_wait); // ID后的部分是否清空
assign clear_afterID = id_csrOrder != 0 && ~id_afterIDClear;  // 是否需要等待id之后的流水级清空
// if 的 axi 读信号
wire if_r_valid_i, if_r_ready_o;
wire [63:0] if_data_read_o;
wire [63:0] if_r_addr_i;
wire [2:0] if_r_size_i;
wire if_data_valid, if_data_ready;
ysyx_041207_IF rxIF(clock, reset, flush, bubble, ex_jal_o, ex_jalr_o, ex_dbranch_o, ex_pc_panic_o || clint_i, ex_aluRes, csr_mtvec, csr_mepc, ex_pc_o, ex_imm_o, ex_forward_rs1_o, if_inst, if_pc, if_r_valid_i, if_r_ready_o, if_data_read_o, if_r_addr_i, if_r_size_i, if_data_valid, if_data_ready, id_pc_mret);

ysyx_041207_axi_switch rx_axi_switch (clock, reset,
mem_r_valid_i, mem_r_ready_o, mem_data_read_o, mem_r_addr_i, mem_r_size_i, mem_data_valid, mem_data_ready,
if_r_valid_i, if_r_ready_o, if_data_read_o, if_r_addr_i, if_r_size_i, if_data_valid, if_data_ready,
rx_r_valid_i, rx_r_ready_o, rx_data_read_o, rx_r_addr_i, rx_r_size_i, rx_data_valid, rx_data_ready
);
ysyx_041207_axi_rw rx_axi(clock, 
reset, rx_r_valid_i, rx_r_ready_o, rx_data_read_o, rx_r_addr_i, rx_r_size_i, rx_data_valid, rx_data_ready,
rx_w_valid_i, rx_w_ready_o, rx_data_write_i, rx_w_addr_i, rx_w_mask_i, rx_w_valid_o, rx_w_ready_i, 
io_master_awready,io_master_awvalid,io_master_awaddr,io_master_awid,io_master_awlen,io_master_awsize,io_master_awburst,io_master_wready,io_master_wvalid,io_master_wdata,io_master_wstrb,io_master_wlast,io_master_bready,io_master_bvalid,io_master_bresp,io_master_bid,io_master_arready,io_master_arvalid,io_master_araddr,io_master_arid,io_master_arlen,io_master_arsize,io_master_arburst,io_master_rready,io_master_rvalid,io_master_rresp,io_master_rdata,io_master_rlast,io_master_rid,rx_w_size_i,
io_sram0_addr,io_sram0_cen,io_sram0_wen,io_sram0_wmask,io_sram0_wdata,io_sram0_rdata,io_sram1_addr,io_sram1_cen,io_sram1_wen,io_sram1_wmask,io_sram1_wdata,io_sram1_rdata,io_sram2_addr,io_sram2_cen,io_sram2_wen,io_sram2_wmask,io_sram2_wdata,io_sram2_rdata,io_sram3_addr,io_sram3_cen,io_sram3_wen,io_sram3_wmask,io_sram3_wdata,io_sram3_rdata

);
//io_sram4_addr,io_sram4_cen,io_sram4_wen,io_sram4_wmask,io_sram4_wdata,io_sram4_rdata,io_sram5_addr,io_sram5_cen,io_sram5_wen,io_sram5_wmask,io_sram5_wdata,io_sram5_rdata,io_sram6_addr,io_sram6_cen,io_sram6_wen,io_sram6_wmask,io_sram6_wdata,io_sram6_rdata,io_sram7_addr,io_sram7_cen,io_sram7_wen,io_sram7_wmask,io_sram7_wdata,io_sram7_rdata

/*  id 导线  */

ysyx_041207_decoder decoder(clock, reset, flush, bubble || clear_afterID, if_inst, if_pc, id_aluOperate, id_sel_a, id_sel_b, id_memoryWriteMask, 
id_writeRD, id_jalr, id_jal, id_writeBackDataSelect, id_memoryReadWen, id_sext, id_readNum, id_rs1to32
, id_wMcause, id_mcause,  id_pc_panic, id_pc_mret, id_csrWen, id_dbranch, id_imm, id_r1addr, id_r2addr, id_rwaddr, id_csrOrder, id_writeLen, id_pc_o);
/*  ex 导线  */


ysyx_041207_dataforward data_forward(id_r1addr, id_r2addr, ex_r1data, ex_r2data, ex_writeRD_o, ex_rwaddr_o, ex_writeBackDataSelect_o, ex_aluRes, me_writeRD_o, me_rwaddr_o, wb_writeBackData, ex_forward_rs1, ex_forward_rs2
);

ysyx_041207_alu ex_alu(
    clock,
    reset,
    flush,
    bubble,

    id_pc_panic,
    id_memoryReadWen,
    id_readNum,
    id_writeBackDataSelect,
    id_memoryWriteMask,
    id_sext,
    id_writeRD,
    id_rwaddr,
    id_jal,
    id_jalr,
    id_dbranch,
    id_csrWen,
    id_writeLen,
    id_pc_mret,

    id_pc_o,
    id_aluOperate,
    ex_forward_rs1,
    ex_forward_rs2,
    ex_csr_readData,
    id_imm,
    id_r1addr,
    id_sel_a,
    id_sel_b,
    id_rs1to32,  // rs1 转换为32bit
    ex_aluRes,
    ex_alu_wait,
    
    ex_memoryReadWen_o,
    ex_readNum_o,
    ex_pc_o,
    ex_imm_o,
    ex_writeBackDataSelect_o,
    ex_forward_rs1_o,
    ex_forward_rs2_o,
    ex_memoryWriteMask_o,
    ex_sext_o,
    ex_writeRD_o,
    ex_rwaddr_o,
    ex_jal_o,
    ex_jalr_o,
    ex_dbranch_o,
    ex_csrWen_o,
    ex_csr_readData_o,
    ex_writeLen_o,
    ex_pc_mret_o,
    ex_pc_panic_o
);
// bubble决定下次是否需要重新计算
ysyx_041207_Bubble rx_bubble (ex_alu_wait, id_r1addr, id_r2addr, ex_writeRD_o, ex_rwaddr_o, ex_writeBackDataSelect_o, me_wait_for_axi, bubble);

ysyx_041207_flush rx_flush (ex_jal_o, ex_jalr_o, ex_pc_panic_o, ex_dbranch_o, ex_aluRes, clint_i, ex_pc_mret_o, clear_afterID, flush);

ysyx_041207_Memory mem(clock, reset, clint_ready, ex_memoryReadWen_o, ex_aluRes, ex_forward_rs2_o, ex_memoryWriteMask_o, ex_writeLen_o, ex_sext_o, ex_readNum_o, me_memoryReadData,
ex_pc_o, ex_imm_o, ex_writeBackDataSelect_o, ex_writeRD_o, ex_rwaddr_o, ex_csrWen_o, ex_csr_readData_o, 
// axi接口
rx_w_valid_i, rx_w_ready_o, rx_data_write_i, rx_w_addr_i, rx_w_mask_i, rx_w_size_i, rx_w_valid_o, rx_w_ready_i,
mem_r_valid_i, mem_r_ready_o, mem_data_read_o, mem_r_addr_i, mem_r_size_i, mem_data_valid, mem_data_ready,
me_wait_for_axi, mtimecmp, mtime, me_aluRes_o, me_pc_o, me_imm_o, me_writeBackDataSelect_o, me_writeRD_o, me_rwaddr_o, me_csrWen_o, me_csrValue_o
);

ysyx_041207_WB wb(me_aluRes_o, me_pc_o, me_memoryReadData, me_imm_o, me_csrValue_o, me_writeBackDataSelect_o, wb_writeBackData);

ysyx_041207_RegisterFile #(32, 5, 64) r(clock, reset, wb_writeBackData, me_rwaddr_o, id_r1addr, ex_r1data, id_r2addr, ex_r2data, me_writeRD_o);
ysyx_041207_csrRegister csrRegister(clock, reset, ex_pc_o, ex_pc_mret_o, me_csrWen_o, ex_pc_panic_o, id_imm[11:0], me_imm_o[11:0], me_aluRes_o, id_wMcause, id_mcause, mtime, mtimecmp, csr_mtvec, csr_mepc, ex_csr_readData, clint_i, clint_ready);
endmodule
module ysyx_041207_WB(
    input   [63:0]  alu_c   ,
    input   [63:0]  pc      ,
    input   [63:0]  ramdout ,
    input   [63:0]  imm     ,
    input   [63:0]  csrValue,
    input   [ 2:0]  wd_sel  ,
    output  reg [63:0]  wD
    );
    always @(*)
    begin
        case(wd_sel)
        3'b000:  wD = alu_c  ;
        3'b001:  wD = ramdout;
        3'b010:  wD = pc+4   ;
        3'b011:  wD = imm    ;
        3'b100:  wD = {{(32){alu_c [31]}}, alu_c [31:0]};
        3'b101:  wD = csrValue;
        default: wD = 64'h0  ;
        endcase
    end
endmodule

